news 2026/9/9 13:49:40

React Router 如何编写 Resource Route 让路由直接返回 PDF、JSON 等响应而非组件?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
React Router 如何编写 Resource Route 让路由直接返回 PDF、JSON 等响应而非组件?

React Router 如何编写 Resource Route 让路由直接返回 PDF、JSON 等响应而非组件?

【免费下载链接】react-routerDeclarative routing for React项目地址: https://gitcode.com/GitHub_Trending/re/react-router

如果你需要在 React Router 应用中让某个 URL 直接返回 PDF 文件、JSON 数据、图片甚至 webhook 响应,而不是渲染一段界面,官方文档把这个能力叫做Resource Routes:服务端渲染时,路由可以提供"资源"而不是组件(见 docs/how-to/resource-routes.md)。

Resource Routes 适用于framework 模式和 data 模式(文档标注[MODES: framework, data])。完成本场景的目标是:让一个路由不导出组件,由loader/action直接生成Response,并在应用的其他页面正确链接到它。

让路由变成 Resource Route:不导出组件即可

路由"按约定"成为 resource route 的条件只有一个:它的模块导出loaderaction,但不导出 default 组件(docs/how-to/resource-routes.md)。

以"返回 PDF 报告"为例,先在路由配置中注册路由:

route("/reports/pdf/:id", "pdf-report.ts");

然后编写路由模块,注意没有 default export,这就是它成为 resource route 的关键:

import type { Route } from "./+types/pdf-report"; export async function loader({ params }: Route.LoaderArgs) { const report = await getReport(params.id); const pdf = await generateReportPDF(report); return new Response(pdf, { status: 200, headers: { "Content-Type": "application/pdf", }, }); }

getReportgenerateReportPDF是你自己业务代码中的函数,Content-Type: application/pdf声明了响应体是 PDF。换成 JSON 响应时同理,返回Response并带上对应的Content-Type即可。

从页面链接到 Resource Route:必须用整页导航

resource route 不返回组件,所以不能用 React Router 的客户端路由去访问它。链接到 resource route 时必须使用<a>标签,或带reloadDocument属性的<Link>;否则 React Router 会尝试走客户端路由,此时你会收到一条有用的错误提示(文档原话:"you'll get a helpful error message if you make this mistake")。

<Link reloadDocument to="/reports/pdf/123"> View as PDF </Link>

reloadDocument的含义见 docs/api/components/Link.md:点击时不走客户端路由,浏览器像处理普通<a href>一样完成整页导航。

处理不同的 HTTP 方法

同一个 resource route 可以用loaderaction分别响应不同方法(docs/how-to/resource-routes.md):

  • GET请求由loader处理;
  • POST、PUT、PATCH、DELETEaction处理。
import type { Route } from "./+types/resource"; export function loader(_: Route.LoaderArgs) { return Response.json({ message: "I handle GET" }); } export function action(_: Route.ActionArgs) { return Response.json({ message: "I handle everything else", }); }

上面这段代码同时也是文档给出的 JSON 响应示例:Response.json直接生成带 JSON 编码的响应。

返回类型怎么选:Response 还是 data()

Resource route 对返回类型是灵活的,可以返回Response实例,也可以返回data()对象。文档给出的判断标准是:

  • 面向外部消费的 resource route,返回Response实例——响应编码在代码里是显式的,不用去猜 React Router 内部如何把data()转换成Response
  • fetcher<Form>提交访问的 resource route,返回data()——与 UI 路由的 loader/action 保持一致,并允许通过data()/Await把 promise 流式传送到 UI。

data()的签名是function data<D>(data: D, init?: number | ResponseInit),用于在不强制序列化为真正Response的情况下携带headers/status(docs/api/utils/data.md):

import { data } from "react-router"; export async function action({ request }: Route.ActionArgs) { let formData = await request.formData(); let item = await createItem(formData); return data(item, { headers: { "X-Custom-Header": "value" }, status: 201, }); }

错误处理:什么时候触发 handleError,什么时候不触发

这一节直接决定你的 resource route 出错时客户端和服务器各自看到什么(docs/how-to/resource-routes.md):

抛出Error(或Response/data()以外的任何东西)会触发handleError,并产生 500 HTTP 响应:

export function action() { let db = await getDb(); if (!db) { // Fatal error - return a 500 response and trigger `handleError` throw new Error("Could not connect to DB"); } // ... }

handleError是在entry.server.tsx中导出的可选函数,用于接管服务端错误的日志记录与上报(默认行为是打到 console)。

只要 resource route 生成了一个Response(通过new Response()data()),就视为执行成功,不会触发handleError——因为 API 已经为 HTTP 请求产出了 Response。这对 thrown response 和带 4xx/5xx 状态码的 returned response 同样成立。文档说明这个行为与fetch()一致:fetch()收到 4xx/5xx 响应时也不会返回 rejected promise。

export function action() { // Non-fatal error - don't trigger `handleError`: throw new Response( { error: "Unauthorized" }, { status: 401 }, ); }

文档还指出throw new Response(...)return new Response(...)throw data(...)return data(...)这几种写法在上述 401 示例中等价。

Error Boundary 只在 resource route 从 UI 访问时才相关:当它被fetcher调用或<Form>提交访问时,throw会冒泡到最近的 UIErrorBoundary。直接通过浏览器整页导航访问时不涉及 Error Boundary。

验证与限制

按上面的路径做完后,可以用文档给出的行为本身作为核对依据:

  1. 用 GET 请求访问该路由,应命中loader;用 POST/PUT/PATCH/DELETE 请求,应命中action——两个方法各返回不同的 JSON 时即可确认分派正确;
  2. 在页面中点击指向 resource route 的普通<Link>(不带reloadDocument),应得到文档所说的 helpful error message;换成<a><Link reloadDocument>后走整页导航;
  3. resource route 中throw new Error(...)时应得到 500 响应并触发handleErrorthrow/return401Response时客户端直接收到 401,且不触发handleError

限制方面注意两点前提:Resource Routes 只在服务端渲染(framework/data 模式)场景下按上述约定生效;如果模块不小心导出了 default 组件,它就不再是 resource route,上述"无 default export 即资源路由"的约定不再成立。

想进一步控制响应细节,可继续查阅 entry.server.tsx 中的handleError(自定义错误处理)与handleDataRequest(修改 data request 响应)两个可选导出;链接行为见 Link 的reloadDocument参数说明。

【免费下载链接】react-routerDeclarative routing for React项目地址: https://gitcode.com/GitHub_Trending/re/react-router

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/9 13:48:58

推理阶段不同batch size对大模型推理结果的影响

SGLang最新版本提供了确定性推理的方法:SGLang的确定性推理 !!!Thinking Machines Lab对这个问题基本上画上了句号&#xff0c;在其官方blog 大模型推理阶段&#xff0c;进行batch inference批处理推理解码&#xff0c;会像预期的那样速度很快推完吗&#xff1f;会不会有什么问…

作者头像 李华
网站建设 2026/9/9 13:48:40

编码智能体崛起:从代码补全到自主完成任务

Simon Willison 是我在开发者社区里一直比较信任的一个观察者。他不是那种只会转发新闻稿的人&#xff0c;而是真的会把手上的工具拆开、试用、写测试、然后告诉你哪里好用哪里难用。最近他连着好几期内容都在聊同一个话题&#xff1a;OpenAI 内部的研究节奏明显加快了&#xf…

作者头像 李华
网站建设 2026/9/9 13:47:47

信息论视角下的复杂系统:用编码理论平衡确定性与不确定性

通信的根本问题&#xff0c;是在一点精确地或近似地复现另一点选择的消息。香农这句话已经被人引用过无数遍了&#xff0c;但我在做了多年复杂系统仿真、又用信息论与编码理论拆解各种系统行为之后&#xff0c;发现绝大多数人都把重点放在“精确复现”四个字上&#xff0c;却忽…

作者头像 李华
网站建设 2026/9/9 13:46:05

STM32F103 LoRa代码整理实战:基于SX1278的无线通信架构与移植指南

简介&#xff1a;正点原子LORA代码整理版面向STM32F103平台&#xff0c;从原子哥原始工程中删去屏显、按键等外围代码&#xff0c;重写后只保留LORA通信的收发核心&#xff0c;适合需要快速搭建点对点无线链路、做数据透传或二次开发的嵌入式开发者。代码剥离了与通信无关的干扰…

作者头像 李华
网站建设 2026/9/9 13:45:44

GPU利用率99%却训练慢?用PyTorch Profiler与Kineto Trace定位性能瓶颈

我刚开始做GPU性能优化那阵子&#xff0c;就遇到过一件让我特别困惑的事&#xff1a;一块训练卡&#xff0c;nvidia-smi里显示的利用率已经到 99%&#xff0c;任谁看都是“满负荷运转”&#xff0c;可训练一个 step 的实际耗时就是压不下去。后来我借着 PyTorch Profiler 背后的…

作者头像 李华
网站建设 2026/9/9 13:45:33

RESTful API设计最佳实践:Python后端实战指南

作为一个常年写Python后端的人&#xff0c;我见过太多“能跑就行”的接口了&#xff1a;有的是随手用Flask写几个路由&#xff0c;URL命名随心所欲&#xff0c;动词名词混在一起用&#xff1b;有的是所有接口统一返回{"code": 0, "msg": "success&quo…

作者头像 李华