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

Cloud Run部署Flask-SocketIO服务遇Polling 400错误求助

问题排查:Flask-SocketIO部署GCP Cloud Run后Polling 400错误

我使用Python-socketio结合Flask监听GCP Pub/Sub主题,获取消息后推送给React应用。本地运行完全正常,但将服务部署到GCP Cloud Run后,客户端轮询时出现400错误。客户端初始启动时显示已连接,但向Pub/Sub主题发送消息时触发该错误。

服务端代码(Flask-SocketIO)

from flask import Flask, request, jsonify
from flask_socketio import SocketIO
import base64
import json
import humps
import os

app = Flask(__name__)
socketio = SocketIO(app, cors_allowed_origins="*", cors_allowed_methods="*")

@app.route('/', methods=['POST'])
def receive_pubsub_message():
    publish_message = request.get_json()

    if "message" in publish_message and "data" in publish_message["message"]:
        # Decode Pub/Sub message
        message_data = base64.b64decode(publish_message["message"]["data"]).decode("utf-8")
        request_json = humps.decamelize(json.loads(message_data))
    else:
        # Handle regular JSON payload (if necessary)
        request_json = humps.decamelize(request.get_json())
    print("request: ", request_json)
    
    # Emit the decoded message to all connected clients
    socketio.emit('new_message', request_json)
    print("Emitting new_message event to clients: ", request_json)

    # Acknowledge the Pub/Sub message by returning a 200 response
    return jsonify({}), 200


if __name__ == '__main__':
    socketio.run(app, debug=True, host='0.0.0.0', port=int(os.environ.get('PORT', 8081)))

客户端代码(React)

import React, { useEffect, useState } from "react";
import io from "socket.io-client";

function App() {
  const [messages, setMessages] = useState([]);

  useEffect(() => {

    // const socket = io("http://localhost:8081");

    const socket = io(
      "wss://xxx-uc.a.run.app"
    );

    socket.on("connect", () => {
      console.log("Connected to server: ", { socket });
    });

    // Listen for incoming messages
    socket.on("new_message", (msg) => {
      console.log("new message: ", { msg });
      // Use the callback function form of setMessages to ensure state updates properly
      setMessages((prevMessages) => [...prevMessages, JSON.stringify(msg)]);
    });

    return () => {
      socket.disconnect();
    };
  }, []); // Empty dependency array to run once on component mount

  return (
    <div className="App">
      <h1>Chat Application</h1>
      <div className="message-list">
        {messages.map((msg, idx) => (
          <div className="message" key={idx}>
            {msg}
          </div>
        ))}
      </div>
    </div>
  );
}

export default App;

错误现象

部署到Cloud Run后,客户端发起的轮询请求返回400状态码,请求地址类似:https://xxx-uc.a.run.app/socket.io/?EIO=4&transport=polling&t=Oiwn41V&sid=KenZXFDBdawUL3opAAAA

排查方案

  • 开启Cloud Run会话亲和性:SocketIO需要客户端始终连接到同一服务实例,Cloud Run默认关闭会话亲和性,导致后续轮询请求被路由到其他实例,实例无法识别之前生成的会话ID(sid),返回400。进入Cloud Run服务设置,找到会话亲和性选项并开启。
  • 适配生产级异步模式:本地debug模式使用Flask自带服务器,部署到Cloud Run需使用生产级异步引擎。确保requirements.txt包含eventlet,修改启动代码关闭debug并指定异步模式:
    if __name__ == '__main__':
        socketio.run(app, debug=False, host='0.0.0.0', port=int(os.environ.get('PORT', 8081)), async_mode='eventlet')
    
  • 优化CORS配置:避免使用通配符*作为cors_allowed_origins,显式指定React应用的域名,同时开启凭证支持(如果需要):
    socketio = SocketIO(app, cors_allowed_origins=["https://your-react-app-domain.com"], allow_credentials=True)
    
  • 查看Cloud Run日志:检查服务端日志,若出现Invalid session ID类错误,可确认是会话亲和性导致的问题;若有其他错误信息,可进一步定位根源。
  • 验证Pub/Sub推送的实例一致性:如果开启会话亲和性后仍有问题,需确认Pub/Sub的推送请求是否路由到了客户端连接的实例,不过该场景下的400错误优先关联客户端轮询的会话问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 11:00:32