Cloud Run经反向代理后WebSocket连接失败问题求助
Cloud Run + WebSocket 自定义域名对接问题排查与解决
核心问题
长期使用Ambassador/Emissary作为API网关,采用架构客户端 -> Ambassador/Emissary -> Cloud Run -> FastAPI,已配置host_rewrite解决404问题,但WebSocket连接始终失败(客户端返回1006错误);相同配置对接GKE Autopilot时可正常运行。后续尝试改用Firebase Hosting路由(客户端 -> Firebase Hosting重写 -> Cloud Run -> FastAPI),WebSocket仍无法正常工作。
关键排查点与修复方案
1. Cloud Run WebSocket的强制要求
Cloud Run对WebSocket请求有严格的头信息要求,必须确保:
- 请求头包含
Upgrade: websocket和Connection: Upgrade,且这两个头不能被网关修改或移除 - 网关必须透传所有WebSocket相关头,包括
Sec-WebSocket-Key、Sec-WebSocket-Version、Sec-WebSocket-Protocol等
2. Ambassador/Emissary配置修正
针对映射配置,需补充以下关键设置:
- 添加
preserve_host: false,配合host_rewrite确保Host头正确传递给Cloud Run - 显式配置允许WebSocket升级:
allow_upgrade: ["websocket"] - 禁用缓存相关头,避免网关干扰WebSocket连接请求
示例配置:
apiVersion: getambassador.io/v3alpha1 kind: Mapping metadata: name: ws-mapping spec: prefix: /ws/ service: 你的Cloud Run服务域名.a.run.app host_rewrite: 你的Cloud Run服务域名.a.run.app preserve_host: false allow_upgrade: ["websocket"] headers: remove: - Cache-Control - Pragma
3. Firebase Hosting的WebSocket支持调整
Firebase Hosting默认对WebSocket转发有限制,需修改firebase.json:
- 配置重写规则指向Cloud Run服务
- 为WebSocket路径添加允许升级的头信息
示例配置:
{ "hosting": { "rewrites": [ { "source": "/ws/**", "run": { "serviceId": "你的Cloud Run服务ID", "region": "你的服务区域" } } ], "headers": [ { "source": "/ws/**", "headers": [ { "key": "Upgrade", "value": "websocket" }, { "key": "Connection", "value": "Upgrade" } ] } ] } }
注意:Firebase Hosting的WebSocket支持仅在特定区域可用,需确保Cloud Run服务未配置强制HTTPS重定向导致头信息丢失。
4. Cloud Run服务端验证
在FastAPI中确保WebSocket端点正确处理请求,示例代码:
from fastapi import FastAPI, WebSocket app = FastAPI() @app.websocket("/ws/{client_id}") async def websocket_endpoint(websocket: WebSocket, client_id: str): await websocket.accept() while True: data = await websocket.receive_text() await websocket.send_text(f"收到消息: {data}")
同时查看Cloud Run服务日志,确认请求是否到达、头信息是否正确传递。
验证步骤
用curl测试WebSocket握手:
curl -i -N -H "Connection: Upgrade" -H "Upgrade: websocket" -H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" -H "Sec-WebSocket-Version: 13" https://你的自定义域名/ws/test
若返回101 Switching Protocols,说明握手成功。
内容的提问来源于stack exchange,提问作者Martol1ni
相关产品推荐
相关产品推荐

