资源路由不是应用程序 UI 的一部分,但仍然是应用程序的一部分。它们可以发送任何类型的响应。
Remix 中的大多数路由都是 UI 路由,或者说是实际渲染组件的路由。但是路由并不总是必须渲染组件。在少数情况下,您希望将路由用作网站的通用端点。以下是一些示例
如果路由未导出默认组件,则可以用作资源路由。如果使用 GET
调用,则返回加载器的响应,并且也不会调用任何父路由加载器(因为这些是 UI 所需的,但这不是 UI)。如果使用 POST
调用,则调用操作的响应。
例如,考虑一个渲染报告的 UI 路由,请注意链接
export 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 版本。为了实现这一点,我们可以在它下面创建一个资源路由。请注意,它没有组件:这使其成为资源路由。
export 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
获取数据并渲染组件。不要太担心,如果您犯了这个错误,您会收到有用的错误消息。
您可能希望在资源路由中添加文件扩展名。这很棘手,因为 Remix 的路由文件命名约定之一是将 .
变为 /
,这样您就可以在不嵌套 UI 的情况下嵌套 URL。
要在路由的路径中添加 .
,请使用 []
转义字符。 我们的 PDF 路由文件名将像这样更改
# original
# /reports/123/pdf
app/routes/reports.$id.pdf.ts
# with a file extension
# /reports/123.pdf
app/routes/reports.$id[.pdf].ts
# or like this, the resulting URL is the same
app/routes/reports.$id[.]pdf.ts
要处理 GET
请求,请导出一个 loader 函数
import type { LoaderFunctionArgs } from "@remix-run/node"; // or cloudflare/deno
import { 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
请求,请导出一个 action 函数
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,以便在新的提交推送到存储库时接收来自 GitHub 的通知
import crypto from "node:crypto";
import type { ActionFunctionArgs } from "@remix-run/node"; // or cloudflare/deno
import { 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);
};