路由

Nitro 支持文件系统路由,自动将文件映射到路由。通过将代码分割与编译路由相结合,它消除了对 runtime router 的需求,只保留了最小的编译逻辑。
Nitro v3 Alpha 文档仍在开发中——可能会有更新、不完善的地方和偶尔的不准确信息。

请求处理器

Nitro 请求处理器是一个接受 event 对象的函数,该对象是一个 H3Event 对象。

import type { H3Event } from "nitro/h3";

export default (event: H3Event) => {
  return "world";
}

文件系统路由

Nitro 为 API routes 支持基于文件的路由(文件自动映射到 h3 routes)。定义路由就像在 api/routes/ 目录中创建文件一样简单。

每个文件只能定义一个 handler,可将 HTTP 方法附加到文件名来定义特定的请求方法。

routes/
  api/
    test.ts      <-- /api/test
  hello.get.ts   <-- /hello (仅 GET)
  hello.post.ts  <-- /hello (仅 POST)
vite.config.ts

通过创建子目录嵌套路由。

routes/
  api/
    [org]/
      [repo]/
        index.ts   <-- /api/:org/:repo
        issues.ts  <-- /api/:org/:repo/issues
      index.ts     <-- /api/:org
package.json

静态路由

首先,在 routes/routes/api/ 目录中创建一个文件。文件名将是路由路径。

然后,导出一个 fetch 兼容的函数:

routes/api/test.ts
import { defineHandler } from "nitro/h3";

export default defineHandler(() => {
  return { hello: "API" };
});

动态路由

单个参数

要定义带有参数的路由,使用 [<param>] 语法,其中 <param> 是参数的名称。参数将在 event.context.params 对象中可用,或使用 getRouterParam 实用程序。

routes/hello/[name].ts
import { defineHandler } from "nitro/h3";

export default defineHandler((event) => {
  const { name } = event.context.params;

  return `Hello ${name}!`;
});

使用参数 /hello/nitro 调用路由,你将得到:

Response
Hello nitro!

多个参数

你可以使用 [<param1>]/[<param2>] 语法在路由中定义多个参数,其中每个参数是一个文件夹。你不能在单个文件名或文件夹中定义多个参数。

routes/hello/[name]/[age].ts
import { defineHandler } from "nitro/h3";

export default defineHandler((event) => {
  const { name, age } = event.context.params;

  return `Hello ${name}! You are ${age} years old.`;
});

捕获所有参数

你可以使用 [...<param>] 语法捕获 URL 的所有剩余部分。这将包括 / 在参数中。

routes/hello/[...name].ts
import { defineHandler } from "nitro/h3";

export default defineHandler((event) => {
  const { name } = event.context.params;

  return `Hello ${name}!`;
});

使用参数 /hello/nitro/is/hot 调用路由,你将得到:

Response
Hello nitro/is/hot!

特定请求方法

你可以将 HTTP 方法附加到文件名,以强制路由仅匹配特定的 HTTP 请求方法,例如 hello.get.ts 将仅匹配 GET 请求。你可以使用任何你想要的 HTTP 方法。

// routes/users/[id].get.ts
import { defineHandler } from "nitro/h3";

export default defineHandler(async (event) => {
  const { id } = event.context.params;

  // 对 id 做一些操作

  return `User profile!`;
});

捕获所有路由

你可以创建一个特殊的路由,它将匹配所有未被任何其他路由匹配的路由。这对于创建默认路由很有用。

要创建捕获所有路由,创建一个名为 [...].ts 的文件。

routes/[...].ts
import { defineHandler } from "nitro/h3";

export default defineHandler((event) => {
  return `Hello ${event.url}!`;
});

环境特定的处理器

你可以通过向文件名添加 .dev.prod.prerender 后缀来指定仅在特定构建中包含的路由,例如:routes/test.get.dev.tsroutes/test.get.prod.ts

你可以通过 handlers[] 配置的程序化路由注册来指定多个环境或将预设名称指定为环境。

中间件

Nitro 路由中间件可以钩入请求生命周期。

中间件可以在请求被处理之前修改请求,而不是之后。

中间件在 middleware/ 目录中自动注册。

middleware/
  auth.ts
  logger.ts
  ...
routes/
  hello.ts

简单中间件

中间件的定义与路由处理器完全相同,唯一的例外是它们不应该返回任何内容。 从中间件返回的行为就像从请求返回一样——返回的值将作为响应返回,并且不会运行进一步的代码。

middleware/auth.ts
import { defineHandler } from "nitro/h3";

export default defineHandler((event) => {
  // 扩展或修改 event
  event.context.user = { name: "Nitro" };
});

middleware/ 目录中的中间件会自动为所有路由注册。如果你想为特定路由注册中间件,请参阅对象语法事件处理器

从中间件返回任何内容都会关闭请求,应该避免!从中间件返回的任何值都将是响应,并且不会执行进一步的代码,但是不建议这样做!

路由元数据

你可以在事件处理器文件中使用 defineRouteMeta 宏在构建时定义路由处理器元数据。

🚧 此功能目前是实验性的。
routes/api/test.ts
import { defineRouteMeta } from "nitro/runtime";
import { defineHandler } from "nitro/h3";

defineRouteMeta({
  openAPI: {
    tags: ["test"],
    description: "测试路由描述",
    parameters: [{ in: "query", name: "test", required: true }],
  },
});

export default defineHandler(() => "OK");
此功能目前可用于指定 OpenAPI 元数据。有关可用的 OpenAPI 选项,请参阅 swagger 规范。

执行顺序

中间件按目录列表顺序执行。

middleware/
  auth.ts <-- 第一个
  logger.ts <-- 第二个
  ... <-- 第三个

使用数字前缀来控制它们的执行顺序。

middleware/
  1.logger.ts <-- 第一个
  2.auth.ts <-- 第二个
  3.... <-- 第三个
请记住,文件名按字符串排序,因此例如如果你有 3 个文件 1.filename.ts2.filename.ts10.filename.ts10.filename.ts 将在 1.filename.ts 之后。为了避免这种情况,如果你在同一目录中有超过 10 个中间件,请在 1-9 前加上 0,如 01

请求过滤

中间件在每个请求上执行。

应用自定义逻辑将它们范围限定到特定条件。

例如,你可以使用 URL 将中间件应用到特定路由:

middleware/auth.ts
import { defineHandler } from "nitro/h3";

export default defineHandler((event) => {
  // 只会为 /auth 路由执行
  if (event.url.pathname.startsWith('/auth')) {
    event.context.user = { name: "Nitro" };
  }
});

错误处理

你可以使用 H3 中可用的实用程序来处理路由和中间件中的错误。

错误发送回客户端的方式取决于路由的路径。对于大多数路由,默认情况下 Content-Type 设置为 text/html,并提供一个简单的 html 错误页面。如果路由以 /api/ 开头(因为它位于 api/routes/api/ 中),默认将更改为 application/json,并将发送 JSON 对象。

此行为可以被某些请求属性覆盖(例如:AcceptUser-Agent 头)。

路由规则

Nitro 允许你在配置的每个路由的顶级添加逻辑。它可以用于重定向、代理、缓存和为路由添加头。

它是从路由模式(遵循 rou3)到路由选项的映射。

当设置 cache 选项时,匹配模式的处理器将自动用 defineCachedEventHandler 包装。请参阅缓存指南以了解有关此函数的更多信息。

swr: true|numbercache: { swr: true, maxAge: number } 的快捷方式

你可以在 nitro.routeRules 选项中设置路由规则。

nitro.config.ts
import { defineNitroConfig } from "nitro/config";

export default defineConfig({
  routeRules: {
    '/blog/**': { swr: true },
    '/blog/**': { swr: 600 },
    '/blog/**': { static: true },
    '/blog/**': { cache: { /* 缓存选项*/ } },
    '/assets/**': { headers: { 'cache-control': 's-maxage=0' } },
    '/api/v1/**': { cors: true, headers: { 'access-control-allow-methods': 'GET' } },
    '/old-page': { redirect: '/new-page' },
    '/old-page/**': { redirect: '/new-page/**' },
    '/proxy/example': { proxy: 'https://example.com' },
    '/proxy/**': { proxy: '/api/**' },
  }
});