当我使用firebase重写时,云运行api服务响应中断



firebase Sveltekit客户端应用程序和服务器api使用谷歌云运行的托管容器。当我使用云运行url:https://app...-4ysldefc4nq-uc.a.run.app/

时,这工作得很好但是,当我使用firebase重写客户端工作正常使用:https://vc-ticker.web.app/...,但从API服务接收502和504响应。云运行日志不显示任何错误,接收客户端获取POST请求并返回一个Readablestream响应。
但是当使用重写时,这个API服务响应流永远不会到达。

firebase.json

{
"hosting": {
"public": "public",   !! NOT used, cloud run hosts the app
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [
{
"source": "**",
"run": {
"serviceId": "vc-ticker-app",
"region": "us-central1"
}
}
]
}
}

+页面。瘦客户机API请求:

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;
}
// response ok: parse multi json chunks => array => set 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");
});

我使用Sveltekit适配器节点来构建应用程序。

From firebase support:

我从工程团队那里得到了答案。不幸的是,Firebase Hosting目前不支持流响应。我已经创建了一个功能请求,所以他们会考虑实现它。

请注意,提交一个功能请求并不能保证它将被实现。敬请关注发行说明。

我知道这不是你期望从我这里得到的答案,但不幸的是我无能为力。

使用重写规则,您可以将匹配特定模式的请求定向到单个目的地。检查你的防火基地。并验证托管部分中的重写配置是否与部署的容器映像中的重定向serviceId名称相同,如下面的示例

"hosting": {// ...
// Add the "rewrites" attribute within "hosting"
"rewrites": [ {
"source": "/helloworld",
"run": {
"serviceId": "helloworld",  // "service name" (from when you [deployed the container image][3])
"region": "us-central1"     // optional (if omitted, default is us-central1)
}
} ]
}

重要的是要注意Firebase Hosting受60秒请求超时的影响。如果你的应用需要超过60秒来运行,你会收到一个HTTPS状态码504(请求超时)。要支持需要较长计算时间的动态内容,请考虑使用灵活的App Engine环境。
您还应该查看主机配置页面以获取有关重写规则的更多详细信息。您还可以了解各种主机配置响应的优先级顺序。

我让它与云运行api服务(cors)的外部链接一起工作。但是我仍然不明白为什么没有cors就不能只使用firebase重写。

+页面。svelte客户机API请求更新:
现在使用GET和认证令牌来验证端点服务器上的api请求

const search = new URLSearchParams(params);
const apiHost = "https://fs-por....-app-4y...q-uc.a.run.app/api/yahoo-finance-streamer";
const response = await fetch(`${apiHost}?${search.toString()}`, {
method: "GET",
headers: {
"auth-token": await getIdToken(),
},
signal: signal,
});

和一个句柄钩子来验证验证令牌和句柄错误:

const logging = true;
const reqUnauthorized = { status: 403, statusText: 'Unauthorized!' };
/** @type {import('@sveltejs/kit').Handle} */
export async function handle({ event, resolve }) {
let response;
if (event.request.method !== "OPTIONS") {
if (event.url.pathname.startsWith('/api')) {
const authToken = event.request.headers.get("auth-token")
const { error = null, decodedToken } = await decodeIdToken(logging, authToken)
if (error) return new Response(error.message, reqUnauthorized);
if (verifyUser(logging, decodedToken) === false) {
return new Response(`user auth failed for: ${decodedToken.email}`, reqUnauthorized);
}
}
response = await resolve(event);
} else { // handle cors preflight OPTIONS
response = new Response("", { status: 200 });
}
response.headers.append('Access-Control-Allow-Headers', "*");
response.headers.append('Access-Control-Allow-Origin', "*");
return response;
}

最新更新