资源路由
このコンテンツはまだ日本語訳がありません。
资源路由不是应用程序 UI 的一部分,但仍然是应用程序的一部分。它们可以发送任何类型的响应。
Remix 中的大多数路由都是 UI 路由,或者实际渲染组件的路由。但路由并不总是必须渲染组件。在少数情况下,您希望将路由用作网站的通用端点。以下是一些示例:
- 适用于移动应用的 JSON API,该应用通过 Remix UI 重用服务器端代码
- 动态生成 PDF
- 动态生成博客文章或其他页面的社交图像
- 适用于 Stripe 或 GitHub 等其他服务的 Webhook
- 动态呈现用户首选主题的自定义属性的 CSS 文件
创建资源路由
如果路由不导出默认组件,则可以将其用作资源路由。如果使用 GET
调用,则返回加载器的响应,并且不会调用任何父路由加载器(因为 UI 需要它们,但这不是 UI)。如果使用 POST
调用,则调用操作的响应。
例如,考虑呈现报告的 UI 路由,请注意链接:
// app/routes/reports.$id.tsxexport async function loader({ params,}: LoaderFunctionArgs) { return json(await getReport(params.id));}
export default function Report() { const report = useLoaderData<typeof loader>(); return ( <div> <h1>{report.name}</h1> <Link to="pdf" reloadDocument> View as PDF </Link> {/* ... */} </div> );}
它链接到页面的 PDF 版本。为了实现这一点,我们可以在其下方创建一个资源路由。请注意,它没有组件:这使它成为资源路由。
// app/routes/reports.$id[.pdf].tsxexport async function loader({ params,}: LoaderFunctionArgs) { const report = await getReport(params.id); const pdf = await generateReportPDF(report); return new Response(pdf, { status: 200, headers: { "Content-Type": "application/pdf", }, });}
当用户单击 UI 路由中的链接时,他们将导航到 PDF。
链接到资源路由
必须在任何资源路由链接上使用
reloadDocument
链接到资源路由时需要注意一个微妙的细节。您需要使用 <Link reloadDocument>
或普通的 <a href>
链接到它。如果您使用普通的 <Link to="pdf">
而不使用 reloadDocument
链接到它,则资源路由将被视为 UI 路由。Remix 将尝试使用 fetch
获取数据并呈现组件。不要太担心,如果您犯了这个错误,您会收到一条有用的错误消息。
URL 转义
您可能希望向资源路由添加文件扩展名。这很棘手,因为 Remix 的路由文件命名约定之一是。
变成 /
,因此您可以嵌套 URL 而不嵌套 UI。
要将 .
添加到路由路径,请使用 []
转义字符。我们的 PDF 路由文件名将更改为如下形式:
# originalapp/routes/reports.$id.pdf.ts
# with a file extension# /reports/123.pdfapp/routes/reports.$id[.pdf].ts
# or like this, the resulting URL is the sameapp/routes/reports.$id[.]pdf.ts
处理不同的请求方法
要处理 GET
请求,请导出加载器函数:
import type { LoaderFunctionArgs } from "@remix-run/node"; // or cloudflare/denoimport { json } from "@remix-run/node"; // or cloudflare/deno
export const loader = async ({ request,}: LoaderFunctionArgs) => { // handle "GET" request
return json({ success: true }, 200);};
要处理 POST
、PUT
、PATCH
或 DELETE
请求,请导出一个动作函数:
import type { ActionFunctionArgs } from "@remix-run/node"; // or cloudflare/deno
export const action = async ({ request,}: ActionFunctionArgs) => { switch (request.method) { case "POST": { /* handle "POST" */ } case "PUT": { /* handle "PUT" */ } case "PATCH": { /* handle "PATCH" */ } case "DELETE": { /* handle "DELETE" */ } }};
Webhook
资源路由可用于处理 webhook。例如,您可以创建一个 webhook,当新的提交推送到存储库时,它会接收来自 GitHub 的通知:
import crypto from "node:crypto";
import type { ActionFunctionArgs } from "@remix-run/node"; // or cloudflare/denoimport { json } from "@remix-run/node"; // or cloudflare/deno
export const action = async ({ request,}: ActionFunctionArgs) => { if (request.method !== "POST") { return json({ message: "Method not allowed" }, 405); } const payload = await request.json();
/* Validate the webhook */ const signature = request.headers.get( "X-Hub-Signature-256" ); const generatedSignature = `sha256=${crypto .createHmac("sha256", process.env.GITHUB_WEBHOOK_SECRET) .update(JSON.stringify(payload)) .digest("hex")}`; if (signature !== generatedSignature) { return json({ message: "Signature mismatch" }, 401); }
/* process the webhook (e.g. enqueue a background job) */
return json({ success: true }, 200);};