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
相关产品推荐
相关产品推荐

