路由

Nitro 支持文件系统路由,自动将文件映射到路由。通过将代码分割与编译后的路由相结合,它消除了对运行时路由器的需要,仅保留最少的编译逻辑。

请求处理器

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

import type { H3Event } from "nitro";

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

文件系统路由

Nitro 支持基于文件的路由来定义你的 API 路由(文件会自动映射到 h3 路由)。定义路由非常简单,只需在 api/routes/ 目录中创建一个文件即可。

你只能为每个文件定义一个处理器,并且可以在文件名后追加 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/
  api/
    (admin)/
      users.ts   <-- /api/users
      reports.ts <-- /api/reports
    (public)/
      index.ts   <-- /api
package.json
路由组不是路由定义的一部分,仅用于组织目的。

静态路由

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

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

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

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

动态路由

单参数

要定义带参数的路由,请使用 [<param>] 语法,其中 <param> 是参数的名称。该参数将在 event.context.params 对象中可用,或者使用 getRouterParam 工具函数。

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

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

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

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

响应
Hello nitro!

多参数

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

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

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";

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

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

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

响应
Hello nitro/is/hot!

特定请求方法

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

支持的方法:getpostputdeletepatchheadoptionsconnecttrace

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

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

  // 对 id 进行一些操作

  return `User profile!`;
});

捕获所有路由

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

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

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

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

环境特定处理器

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

该后缀放在方法后缀之后(如果有的话):

routes/
  env/
    index.dev.ts       <-- /env (仅开发环境)
    index.get.prod.ts  <-- /env (GET, 仅生产环境)
你可以通过 routes 配置使用程序化路由注册来指定多个环境或将预设名称指定为环境。

忽略文件

你可以使用 ignore 配置选项来排除文件不被路由扫描。它接受相对于服务器目录的 glob 模式数组。

nitro.config.ts
import { defineConfig } from "nitro";

export default defineConfig({
  ignore: [
    "routes/api/**/_*",   // 忽略 api/ 中以 _ 开头的文件
    "middleware/_*.ts",    // 忽略以 _ 开头的中间件
    "routes/_*.ts",       // 忽略根路由中以 _ 开头的文件
  ],
});

程序化路由处理器

除了文件系统路由外,你还可以使用 routes 配置选项以程序化方式注册路由处理器。

routes 配置

routes 选项允许你将路由模式映射到处理器:

nitro.config.ts
import { defineConfig } from "nitro";

export default defineConfig({
  routes: {
    "/api/hello": "./server/routes/api/hello.ts",
    "/api/custom": {
      handler: "./server/routes/api/hello.ts",
      method: "POST",
      lazy: true,
    },
    "/virtual": {
      handler: "#virtual-route",
    },
  },
});

每个路由条目可以是一个简单的字符串(处理器路径)或一个具有以下选项的对象:

选项类型描述
handlerstring事件处理器文件或虚拟模块 ID 的路径
methodstring要匹配的 HTTP 方法(getpost 等)
lazyboolean使用懒加载导入处理器
format"web" | "node"处理器类型。"node" 处理器会被转换为兼容 web 的格式
envstring | string[]包含此处理器的环境("dev""prod""prerender" 或预设名称)

handlers 配置

handlers 数组适用于注册具有路由匹配控制权的中间件:

nitro.config.ts
import { defineConfig } from "nitro";

export default defineConfig({
  handlers: [
    {
      route: "/api/**",
      handler: "./server/middleware/api-auth.ts",
      middleware: true,
    },
  ],
});

每个处理器条目支持以下选项:

选项类型描述
routestringHTTP 路径名模式(例如 /test/api/:id/blog/**
handlerstring事件处理器文件或虚拟模块 ID 的路径
methodstring要匹配的 HTTP 方法(getpost 等)
middlewareboolean在路由处理器之前作为中间件运行处理器
lazyboolean使用懒加载导入处理器
format"web" | "node"处理器类型。"node" 处理器会被转换为兼容 web 的格式
envstring | string[]包含此处理器的环境("dev""prod""prerender" 或预设名称)

中间件

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

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

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

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

简单中间件

中间件的定义与路由处理器完全相同,唯一的区别是它们不应该返回任何内容。 从中间件返回的行为类似于从请求返回——该值将作为响应返回,后续代码将不会运行。

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

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

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

从中间件返回任何内容都会关闭请求,应该避免这样做!中间件的任何返回值都将成为响应,后续代码将不会执行,然而不推荐这样做!

路由元数据

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

此功能目前处于实验阶段。
routes/api/test.ts
import { defineRouteMeta } from "nitro";
import { defineHandler } from "nitro";

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

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

执行顺序

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

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";

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

路由作用域中间件

你可以使用 handlers 配置并设置 middleware 选项和特定的 route 来为特定路由模式注册中间件:

nitro.config.ts
import { defineConfig } from "nitro";

export default defineConfig({
  handlers: [
    {
      route: "/api/**",
      handler: "./server/middleware/api-auth.ts",
      middleware: true,
    },
  ],
});

与全局中间件(在 middleware/ 目录中注册,匹配 /**)不同,路由作用域中间件仅对匹配指定模式的请求运行。

错误处理

你可以在路由和中间件中使用 H3 提供的工具 来处理错误。

错误返回给客户端的方式取决于环境。在开发环境中,带有 Accept 请求头为 text/html(如浏览器)的请求将收到 HTML 错误页面。在生产环境中,错误始终以 JSON 格式发送。

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

代码分割

Nitro 为每个路由处理程序创建单独的代码块。代码块在首次请求时按需加载,因此 /api/users 不会加载 /api/posts 的代码。

查看 inlineDynamicImports 以将所有内容打包到单个文件中。

路由规则

Nitro 允许你在配置中为每个路由添加顶层逻辑。可用于重定向、代理、缓存、认证以及为路由添加请求头。

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

When cache option is set, handlers matching pattern will be automatically wrapped with defineCachedHandler. See the cache guide to learn more about this function.

swr: true|numbercache: { swr: true, maxAge: number } 的简写

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

nitro.config.ts
import { defineConfig } from "nitro";

export default defineConfig({
  routeRules: {
    '/blog/**': { swr: true },
    '/blog2/**': { swr: 600 },
    '/blog3/**': { static: true },
    '/blog4/**': { 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/**' },
    '/admin/**': { basicAuth: { username: 'admin', password: 'supersecret' } },
  }
});

规则合并与覆盖

路由规则按照从最不具体到最具体的顺序匹配。当多个规则匹配一个请求时,它们的选项会合并,更具体的规则优先。

你可以使用 false 来禁用由更通用模式设置的规则:

nitro.config.ts
import { defineConfig } from "nitro";

export default defineConfig({
  routeRules: {
    '/api/cached/**': { swr: true },
    '/api/cached/no-cache': { cache: false, swr: false },
    '/admin/**': { basicAuth: { username: 'admin', password: 'secret' } },
    '/admin/public/**': { basicAuth: false },
  }
});

请求头

为匹配的路由设置自定义响应头:

nitro.config.ts
import { defineConfig } from "nitro";

export default defineConfig({
  routeRules: {
    '/api/**': { headers: { 'cache-control': 's-maxage=60' } },
    '**': { headers: { 'x-powered-by': 'Nitro' } },
  }
});

跨域资源共享 (CORS)

使用 cors: true 快捷方式启用 CORS 请求头。这将设置 access-control-allow-origin: *access-control-allow-methods: *access-control-allow-headers: *access-control-max-age: 0

你可以使用 headers 覆盖单个 CORS 请求头:

nitro.config.ts
import { defineConfig } from "nitro";

export default defineConfig({
  routeRules: {
    '/api/v1/**': {
      cors: true,
      headers: { 'access-control-allow-methods': 'GET' },
    },
  }
});

重定向

将匹配的路由重定向到另一个 URL。使用字符串进行简单重定向(默认为 307 状态码),或使用对象进行更精细的控制:

nitro.config.ts
import { defineConfig } from "nitro";

export default defineConfig({
  routeRules: {
    // 简单重定向(307 状态码)
    '/old-page': { redirect: '/new-page' },
    // 自定义状态码的重定向
    '/legacy': { redirect: { to: 'https://example.com/', status: 308 } },
    // 通配符重定向 — 保留模式后的路径
    '/old-blog/**': { redirect: 'https://blog.example.com/**' },
  }
});

代理

将请求代理到另一个 URL。支持内部和外部目标:

nitro.config.ts
import { defineConfig } from "nitro";

export default defineConfig({
  routeRules: {
    // 代理到确切 URL
    '/api/proxy/example': { proxy: 'https://example.com' },
    // 代理到内部路由
    '/api/proxy/**': { proxy: '/api/echo' },
    // 通配符代理 — 保留模式后的路径
    '/cdn/**': { proxy: 'https://cdn.jsdelivr.net/**' },
    // 带选项的代理
    '/external/**': {
      proxy: {
        to: 'https://api.example.com/**',
        // 其他 H3 代理选项...
      },
    },
  }
});

基础认证

使用 HTTP 基础认证保护路由:

nitro.config.ts
import { defineConfig } from "nitro";

export default defineConfig({
  routeRules: {
    '/admin/**': {
      basicAuth: {
        username: 'admin',
        password: 'supersecret',
        realm: '管理区域',  // 可选,显示在浏览器提示框中
      },
    },
    // 为子路径禁用基础认证
    '/admin/public/**': { basicAuth: false },
  }
});

缓存(SWR / 静态)

使用 cacheswrstatic 选项控制缓存行为:

nitro.config.ts
import { defineConfig } from "nitro";

export default defineConfig({
  routeRules: {
    // 启用 stale-while-revalidate 缓存
    '/blog/**': { swr: true },
    // 带 maxAge(秒)的 SWR
    '/blog/posts/**': { swr: 600 },
    // 完整缓存选项
    '/api/data/**': {
      cache: {
        maxAge: 60,
        swr: true,
        // ...其他缓存选项
      },
    },
    // 禁用缓存
    '/api/realtime/**': { cache: false },
  }
});
swr: truecache: { swr: true } 的简写,swr: <number>cache: { swr: true, maxAge: <number> } 的简写。

预渲染

标记路由以在构建时进行预渲染:

nitro.config.ts
import { defineConfig } from "nitro";

export default defineConfig({
  routeRules: {
    '/about': { prerender: true },
    '/dynamic/**': { prerender: false },
  }
});

ISR (Vercel)

为 Vercel 部署配置增量静态再生:

nitro.config.ts
import { defineConfig } from "nitro";

export default defineConfig({
  routeRules: {
    '/isr/**': { isr: true },
    '/isr-ttl/**': { isr: 60 },
    '/isr-custom/**': {
      isr: {
        expiration: 60,
        allowQuery: ['q'],
        group: 1,
      },
    },
  }
});

路由规则参考

选项类型描述
headersRecord<string, string>自定义响应头
redirectstring | { to: string, status?: number }重定向到另一个 URL(默认状态码:307
proxystring | { to: string, ...proxyOptions }将请求代理到另一个 URL
corsboolean启用宽松的 CORS 请求头
cacheobject | false缓存选项(参见 缓存指南
swrboolean | numbercache: { swr: true, maxAge: number } 的简写
staticboolean | number静态缓存的简写
basicAuth{ username, password, realm? } | falseHTTP 基础认证
prerenderboolean启用/禁用预渲染
isrboolean | number | object增量静态再生(Vercel)

运行时路由规则

路由规则可以通过 runtimeConfig 提供,允许通过环境变量覆盖而无需重新构建:

nitro.config.ts
import { defineConfig } from "nitro";

export default defineConfig({
  runtimeConfig: {
    nitro: {
      routeRules: {
        '/api/**': { headers: { 'x-env': 'production' } },
      },
    },
  },
});

配置参考

这些配置选项控制路由行为:

选项类型默认值描述
baseURLstring"/"所有路由的基础 URL
apiBaseURLstring"/api"api/ 目录中路由的基础 URL
apiDirstring"api"API 路由的目录名称
routesDirstring"routes"基于文件的路由的目录名称
serverDirstring | falsefalse用于扫描路由、中间件、插件等的服务器目录
scanDirsstring[][]扫描路由的额外目录
routesRecord<string, string | handler>{}路由到处理程序的映射
handlersNitroEventHandler[][]程序化处理程序注册(主要用于中间件)
routeRulesRecord<string, NitroRouteConfig>{}匹配模式的路由规则
ignorestring[][]文件扫描期间忽略的 glob 模式