未找到处理

未找到 (404) 处理

¥Not Found (404) Handling

当在 Web 服务器上找不到文档时,Remix 会发送 404 状态码 错误。这向机器指示文档不存在:搜索引擎不会索引它,CDN 不会缓存它,等等。如今大多数 SPA 都会将所有内容都返回 200,无论页面是否存在,但对于你来说,今天就此结束!

¥When a document isn't found on a web server, it should send a 404 status code. This indicates to machines that the document is not there: search engines won't index it, CDNs won't cache it, etc. Most SPAs today just serve everything as 200 whether the page exists or not, but for you that stops today!

Remix 网站主要会在两种情况下发送 404 错误:

¥There are two primary cases where a Remix site should send a 404:

  • URL 与应用中的任何路由都不匹配

    ¥The URL doesn't match any routes in the app

  • 你的加载器未找到任何数据

    ¥Your loader didn't find any data

Remix 已经处理了第一种情况,你无需自己抛出响应。它了解你的路由,因此它知道是否没有任何匹配项(请考虑使用 Splat Route 来处理这种情况)。第二种情况由你决定,但它非常简单。

¥Remix already handles the first case, you don't have to throw a response yourself. It knows your routes, so it knows if nothing matched (consider using a Splat Route to handle this case). The second case is up to you, but it's really easy.

如何发送 404

¥How to Send a 404

一旦你发现没有用户所需的内容,就应该抛出一个响应。

¥As soon as you know you don't have what the user is looking for, you should throw a response.

export async function loader({
  params,
}: LoaderFunctionArgs) {
  const page = await db.page.findOne({
    where: { slug: params.slug },
  });

  if (!page) {
    throw new Response(null, {
      status: 404,
      statusText: "Not Found",
    });
  }

  return json(page);
}

Remix 将捕获响应并将你的应用发送到 错误边界 路径。它实际上与 Remix 的自动 错误处理 完全一样,但你收到的不是从 useRouteError() 接收的 Error,而是包含响应 statusstatusText 和提取的 data 的对象。

¥Remix will catch the response and send your app down the Error Boundary path. It's actually exactly like Remix's automatic error handling, but instead of receiving an Error from useRouteError(), you'll receive an object with your response status, statusText, and extracted data.

抛出响应的好处在于,加载器中的代码会停止执行。其余代码无需处理页面是否已定义的问题(这对于 TypeScript 来说尤其方便)。

¥What's nice about throwing a response is that code in your loader stops executing. The rest of your code doesn't have to deal with the chance that the page is defined or not (this is especially handy for TypeScript).

抛出错误还可以确保在加载器失败的情况下,路由组件不会渲染。你的路由组件只需考虑 "快乐路径"。它们不需要待处理状态、错误状态,或者在我们这里的例子里,不需要未找到状态。

¥Throwing also ensures that your route component doesn't render if the loader wasn't successful. Your route components only have to consider the "happy path". They don't need pending states, error states, or in our case here, not-found states.

根错误边界

¥Root Error Boundary

你的应用根目录下可能已经有一个了。这将处理所有未在嵌套路由中处理的抛出的响应。这是一个示例:

¥You probably already have one at the root of your app. This will handle all thrown responses not handled in a nested route. Here's a sample:

export function ErrorBoundary() {
  const error = useRouteError();
  return (
    <html>
      <head>
        <title>Oops!</title>
        <Meta />
        <Links />
      </head>
      <body>
        <h1>
          {isRouteErrorResponse(error)
            ? `${error.status} ${error.statusText}`
            : error instanceof Error
            ? error.message
            : "Unknown Error"}
        </h1>
        <Scripts />
      </body>
    </html>
  );
}
Remix v2.17 中文网 - 粤ICP备13048890号