0

I have a serverless pipeline on Google Cloud. It consists of three total steps:

  1. A video uploader that sends videos to Google Cloud Storage. Working fine.
  2. An eventarc + pub/sub trigger that fires whenever a video is uploaded to GCS to a cloud run application called 'post processor'.
  3. The post processor extracts some information regarding this file and sends a API request to my Django API, to create a history f this recording to my database.

The post processor is implemented using functions_framework.cloud_event. I also created some logs so I could debug it in Google Cloud Logging. Here's one example as follows:

2025-09-24 14:53:05,135 INFO main: RECEIVED DATA FROM EVENTARC (POST-PROCESSING): Original Filename=7614_2025_09_23_16_46_17.mp4, Serial=7614, UTC=2025-09-23T16:46:17+00:00, Duration=0s, Frames=0 

It received all the information correctly... Generated a payload from it and posted a request to my Django API. Payload sent is this:

{ "raw_file": null, "raw_file_gcp": "https://storage.cloud.google.com/homolog-videos/7614_2025_09_23_16_46_17.mp4", "motion_file": null, "event_at": "2025-09-23T16:46:17+00:00", "camera": 7614, "frames_count": 0, "duration_seconds": 0, "event_end_at": "2025-09-23T16:46:17+00:00", "size_mb": 0 } 

However, when seeing the request on my Django API, it receives no payload at all and the requests comes as a GET method instead of the POST method. For example, the request above arrived like this: [GET] /api/recordings/ | From: 34.34.234.34 | Payload: {}

This unintentionally triggers a list endpoint instead of creating a record....

I reproduced my production settings locally, (DEBUG=False, ENVIRONMENT="production", etc) and kept the same Post Processor code and library versions. I used NGrok to process videos sent to GCS, instead of CloudRun, and to my surprise, locally, when outside of Google Cloud Services (Cloud Run) the API correctly received the POST request with the correct JSON... Same exact code as in cloud run, library versions, etc... Behaved as expected with no conversion to GET.

The libraries i'm using are as follows:

functions-framework==3.5.0 cloudevents==1.11.0 cachetools==6.1.0 pytz==2025.1 requests==2.32.5 

It's a small script that only performs this post to the API.

What i'm not getting is what could be causing requests.post made from Cloud Run to result in a GET with a empty body conversion in my Django REST Framework...? Is there a setting in my ingress.yaml setting I should do? A rule, host definition, etc, there that could be causing this issue?

Edit 1

Below is a minimal code example showing how the post processor works, that is activated whenever a GCS upload is finished.

import functions_framework from cloudevents.http import CloudEvent # Triggered by a Cloud Storage "object finalized" event @functions_framework.cloud_event def hello_gcs(cloud_event: CloudEvent): data = cloud_event.data name = data["name"] # e.g. "7614_2025_09_23_16_46_17.mp4" # ...parse metadata and compute (serial, date, duration, frames, filename)... serial, date, duration, frames, filename = process_video(name) create_recording(serial, date, duration, frames, filename) return "OK" 

Where the payload is built and the API call is made:

def create_recording(serial_cam, date, duration, frames, filename): API_URL = os.environ.get("API_URL") API_TOKEN = os.environ.get("API_TOKEN") api = WrapperAPI(API_URL, API_TOKEN) # Build payload payload = { "raw_file": None, "raw_file_gcp": f"https://storage.cloud.google.com/{BUCKET}/{filename}", # ... etc ... A normal payload, nothing fancy. } # Perform the POST recording = api.create(resource="recordings", json=payload, hide_error_msg=False) 

API wrapper (uses requests.post, not GET.):

import requests class WrapperAPI: def __init__(self, base_url, token): self.url = base_url.rstrip("/") self.headers = {"Authorization": token, "Content-Type": "application/json"} def create(self, resource, json, hide_error_msg=False): try: url = f"{self.url}/{resource}/" resp = requests.post(url, json=json, headers=self.headers) # <-- POST resp.raise_for_status() return resp.json() # ... etc ... Exception treatment... No magic here. Just the normal exception treatment you would expect. 

Edit 2

We did some investigation and found some similar threads that have some similar problems. Tho they were not in GKE contexts... When Python’s requests client followed it, it converted the method to GET and dropped the body—explaining exactly why the backend saw a GET with empty payload.

The question was exact 'Python Requests library post interpreted by Django as GET for some reason' and we had exactly the same problem. But we only found this after @shiro answer. We actually found it because of it. I wanted to link it here in case anyone comes across this.

6
  • You assert that you're making a POST and GKE is receiving a GET. Absent evidence, the conclusion is that you're making a GET (and receiving a GET). Please include a minimal repro including the Cloud Run source code and details of how the GKE service is exposed. Commented Sep 24 at 17:25
  • @DazWilkin Of course, I understand anyone would assume that, I would do the same. I edited the question and pasted the source codes as requested. Commented Sep 24 at 19:36
  • Thanks for updating the question! I'm going to try to repro your issue but may not be able to start this until tomorrow Pacific. Commented Sep 24 at 21:13
  • I'm (currently) unable to repro your issue. I'm running your Python code (invoking create_recording directly) against a debug server locally, containerized locally and deploy to a local Kubernetes cluster and every time the server receives POST's Commented Sep 24 at 22:09
  • And deployed to Cloud Run but still using my local Kubernetes cluster, POST's Commented Sep 24 at 22:47

1 Answer 1

1

Your POST became a GET because of an unhandled HTTP redirect.

Your GKE ingress redirected your insecure http:// request to the secure https:// URL. Following this redirect, your requests client automatically changed the method from POST to GET, which is standard, expected web behavior.

You may try to fix the API_URL in your Cloud Run environment variable to use https:// from the start. This prevents the redirect and ensures your POST arrives as intended.

To reliably trace this, inspect the response.history attribute in your Cloud Run client code. This will show the exact redirect that occurred.

Sign up to request clarification or add additional context in comments.

2 Comments

Is it working now?
Awesome! This was exactly the problem. Going further, I found two other questions showing the same behavior, but using NGINX instead of GKE. I talked with a colleague who's a Google Cloud specialist, and it turns out GKE's Ingress YAML was generating rewrite rules that redirected HTTP to HTTPS. That caused the POST to be downgraded to GET by requests. I’ve added the full explanation and related links in Edit 2 — hope it helps others too!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.