使用Firebase Rewrites时Cloud Run API服务响应异常问题
Firebase Rewrite代理Cloud Run流式API返回502/504的解决办法
直接访问Cloud Run的URL时,SvelteKit客户端和服务器API都运行正常;但通过Firebase Hosting的Rewrite规则用vc-ticker.web.app访问时,客户端页面功能正常,API的POST请求却返回502或504错误。Cloud Run日志显示已接收请求并返回ReadableStream,但该流数据从未到达客户端。
当前配置
firebase.json
{ "hosting": { "public": "public", // 未使用,应用由Cloud Run托管 "ignore": [ "firebase.json", "**/.*", "**/node_modules/**" ], "rewrites": [ { "source": "**", "run": { "serviceId": "vc-ticker-app", "region": "us-central1" } } ] } }
客户端流式请求代码(+page.svelte)
const logging = true; const controller = new AbortController(); let reader = null; const signal = controller.signal; async function streamer(params) { console.log("stream with logging:", logging, JSON.stringify(params)); try { const response = await fetch("api/my-ticker", { method: "POST", body: JSON.stringify(params), headers: { "content-type": "application/json", }, signal: signal, }); const stream = response.body.pipeThrough(new TextDecoderStream("utf-8")); reader = stream.getReader(); while (true) { const { value, done } = await reader.read(); if (done || response.status !== 200) { console.log("done response", response.status, done, value); await reader.cancel(`reader done or invalid response: ${response.status}`); reader = null; break; } // 将多块JSON解析为数组后更新store const quotes = {}; JSON.parse(`[${value.replaceAll("}{", "},{")}]`).forEach((each, idx) => { quotes[each.id] = [each.price, each.changePercent]; console.log(`quote-${idx}:`, quotes[each.id]); }); positions.set(quotes); } } catch (err) { console.log("streamer exception", err.name, err); if (reader) { await reader.cancel(`client exception: ${err.name}`); reader = null; } } } $: if ($portfolio?.coins) { const params = { logging, symbols: Object.values($portfolio.symbols), }; streamer(params); } onDestroy(async () => { if (reader) await reader.cancel("client destroyed"); controller.abort(); console.log("finished"); });
问题根因
Firebase Hosting默认代理配置不支持**分块传输编码(Chunked Transfer Encoding)**的流式响应,它会尝试缓冲整个响应后再返回给客户端。而你的API返回的是ReadableStream,属于实时分块传输,Firebase代理无法处理该场景,最终导致超时(504)或代理错误(502)。
解决步骤
1. 修改Firebase Rewrite配置,开启流式支持
在run节点添加配置,强制代理透传流式响应:
{ "hosting": { "public": "public", "ignore": [ "firebase.json", "**/.*", "**/node_modules/**" ], "rewrites": [ { "source": "**", "run": { "serviceId": "vc-ticker-app", "region": "us-central1", "serveHostingAssets": false, "httpHeaders": { "Transfer-Encoding": "chunked", "Cache-Control": "no-cache" } } } ] } }
serveHostingAssets: false:关闭Firebase Hosting的静态资源缓冲逻辑,让所有请求直接转发给Cloud RunTransfer-Encoding: chunked:告知代理保留分块传输格式Cache-Control: no-cache:禁止代理缓冲响应内容
2. 调整Cloud Run API的响应头
在SvelteKit的API路由(如+server.js)中,确保返回响应时携带以下头信息:
export async function POST({ request }) { // 你的流式处理逻辑 const stream = ...; // 生成ReadableStream的代码 return new Response(stream, { headers: { 'Content-Type': 'application/json', 'Transfer-Encoding': 'chunked', 'Connection': 'keep-alive', 'Cache-Control': 'no-cache, no-store' } }); }
这些头信息会明确告知代理不要修改响应内容,直接将分块数据实时转发给客户端。
3. 检查Cloud Run超时设置
Cloud Run默认请求超时为5分钟,如果你的流式连接需要更长时间,可在Cloud Run控制台将服务超时时间调至最大值(60分钟)。
4. 验证请求路径
确认客户端fetch的路径无误,使用相对路径时需确保页面base路径正确,避免请求发错地址。
内容的提问来源于stack exchange,提问作者voscausa
相关产品推荐
相关产品推荐

