You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Cloud Run中requests.post请求被Django识别为GET的问题排查

Google Cloud无服务器流水线POST请求被转为GET的问题

问题概述

我在Google Cloud上搭建了一套无服务器流水线,包含三个步骤:

  • 视频上传器将视频发送至Google Cloud Storage,运行正常;
  • 当视频上传至GCS时,Eventarc + Pub/Sub触发器会触发名为“post processor”的Cloud Run应用;
  • post processor提取文件相关信息后,向我的Django API发送请求,在数据库中创建该录制的历史记录。

post processor基于functions_framework.cloud_event实现,Google Cloud Logging中的日志显示它能正确接收所有信息:

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

并生成如下Payload发送至Django API:

{
  "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
}

但Django API端收到的请求没有任何Payload,且请求方法变为GET而非POST,示例日志:

[GET] /api/recordings/ | From: 34.34.234.34 | Payload: {}

这意外触发了列表接口而非创建记录的接口。

本地复现生产环境设置(DEBUG=False、ENVIRONMENT="production"等),使用相同的post processor代码和依赖版本,通过NGrok处理GCS上传的视频时,Django API能正确接收带有JSON的POST请求,与Cloud Run中的表现完全不同。

使用的依赖库如下:

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

我无法理解为何Cloud Run中执行的requests.post会被Django REST Framework转换为无请求体的GET请求?是否需要在ingress.yaml中配置某些规则或主机定义?


Edit 1:相关代码示例

触发器函数代码

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"

构建Payload并发送请求的代码

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封装类代码

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:调研结论

调研发现,当Python的requests客户端跟随重定向时,会将请求方法转换为GET并丢弃请求体,这正好解释了后端为何收到无Payload的GET请求,我们遇到的问题与同类场景下的问题完全一致。


内容的提问来源于stack exchange,提问作者Raul Chiarella

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 07:54:53