在我的动作函数中,我从第三方api获取数据,需要一些时间。我如何从动作函数重定向而不等待取回,如果取回失败重定向回以前的路由?
export const action: ActionFunction = async ({ request }) => {
const session = await getSession(request.headers.get("Cookie"));
try {
// this takes too much time, and can fail
const apiResponse = await fetch("some-3rd-party-api");
if (apiResponse.status !== 200) throw new Error("API error");
} catch (error) {
return json({ formError: error }, { status: 400 });
}
session.set("mySessionKey", {page: 2});
return redirect(`/next-page`, {
headers: { "Set-Cookie": await commitSession(session) },
});
};
我试着这样做:
fetch("some-3rd-party-api").then().catch(() => {
// redirect back the original route
return redirect("/first-page")}
);
session.set("mySessionKey", {page: 2});
return redirect(`/next-page`, {
headers: { "Set-Cookie": await commitSession(session) },
});
让我们把它分成两步:
- 运行代码异步(后台作业)
- 作业完成后通知用户
运行代码async(后台作业)
Remix不提供处理后台任务的原语。创建后台作业的方式取决于您的服务器环境。- 长时间运行的web服务器,如Express.js将运行你的代码异步(在后台),即使返回一个响应给用户。
- 一旦您向用户返回响应(处理请求),无服务器和边缘函数可能会终止。根据后台任务花费的时间,你可能需要一个更复杂的解决方案。
作业完成后通知用户
你正在寻找一种方式让你的服务器通知你的客户端事件已经发生(服务器推送)。长轮询、WebSockets和服务器发送事件都是有效的选项。我建议你研究一下服务器发送事件(SSE),因为它们很容易用Remix实现。
解决方案可以是这样的:
操作代码:
export const action: ActionFunction = async ({ request }) => {
const session = await getSession(request.headers.get("Cookie"));
fetch("some-3rd-party-api").catch(err => {
// emit error event, which triggers server-sent event
EventEmitter.emit("API error ");
});
session.set("mySessionKey", {page: 2});
return redirect(`/next-page`, {
headers: { "Set-Cookie": await commitSession(session) },
});
};
您可以在Remix repo中找到官方SSE示例。你可以在这里找到一个使用Remix的更简单的SSE示例,它非常接近你需要的。