路由
请求处理器
Nitro 请求处理器是一个接受 event 对象的函数,该对象是 H3Event 对象。
import type { H3Event } from "nitro";
export default (event: H3Event) => {
return "world";
}
import { defineHandler } from "nitro";
// 为了更好的类型推断
export default defineHandler((event) => {
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 的函数:
import { defineHandler } from "nitro";
export default defineHandler(() => {
return { hello: "API" };
});
动态路由
单参数
要定义带参数的路由,请使用 [<param>] 语法,其中 <param> 是参数的名称。该参数将在 event.context.params 对象中可用,或者使用 getRouterParam 工具函数。
import { defineHandler } from "nitro";
export default defineHandler((event) => {
const { name } = event.context.params;
return `Hello ${name}!`;
});
使用参数 /hello/nitro 调用该路由,你将得到:
Hello nitro!
多参数
你可以使用 [<param1>]/[<param2>] 语法在路由中定义多个参数,其中每个参数都是一个文件夹。你不能在单个文件名或文件夹中定义多个参数。
import { defineHandler } from "nitro";
export default defineHandler((event) => {
const { name, age } = event.context.params;
return `Hello ${name}! You are ${age} years old.`;
});
捕获所有参数
你可以使用 [...<param>] 语法捕获 URL 的所有剩余部分。这将把 / 包含在参数中。
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 方法。
支持的方法:get、post、put、delete、patch、head、options、connect、trace。
// routes/users/[id].get.ts
import { defineHandler } from "nitro";
export default defineHandler(async (event) => {
const { id } = event.context.params;
// 对 id 进行一些操作
return `User profile!`;
});
// routes/users.post.ts
import { defineHandler } from "nitro";
export default defineHandler(async (event) => {
const body = await event.req.json();
// 对 body 进行一些操作,比如保存到数据库
return { updated: true };
});
捕获所有路由
你可以创建一个特殊的路由,它将匹配所有未被其他任何路由匹配的路由。这对于创建默认路由很有用。
要创建捕获所有路由,请创建一个名为 [...].ts 的文件。
import { defineHandler } from "nitro";
export default defineHandler((event) => {
return `Hello ${event.url}!`;
});
环境特定处理器
你可以通过在文件名后添加 .dev、.prod 或 .prerender 后缀来指定仅包含在特定构建中的路由,例如:routes/test.get.dev.ts 或 routes/test.get.prod.ts。
该后缀放在方法后缀之后(如果有的话):
routes/
env/
index.dev.ts <-- /env (仅开发环境)
index.get.prod.ts <-- /env (GET, 仅生产环境)
routes 配置使用程序化路由注册来指定多个环境或将预设名称指定为环境。忽略文件
你可以使用 ignore 配置选项来排除文件不被路由扫描。它接受相对于服务器目录的 glob 模式数组。
import { defineNitroConfig } from "nitro/config";
export default defineNitroConfig({
ignore: [
"routes/api/**/_*", // 忽略 api/ 中以 _ 开头的文件
"middleware/_*.ts", // 忽略以 _ 开头的中间件
"routes/_*.ts", // 忽略根路由中以 _ 开头的文件
],
});
程序化路由处理器
除了文件系统路由外,你还可以使用 routes 配置选项以程序化方式注册路由处理器。
routes 配置
routes 选项允许你将路由模式映射到处理器:
import { defineNitroConfig } from "nitro/config";
export default defineNitroConfig({
routes: {
"/api/hello": "./server/routes/api/hello.ts",
"/api/custom": {
handler: "./server/routes/api/hello.ts",
method: "POST",
lazy: true,
},
"/virtual": {
handler: "#virtual-route",
},
},
});
每个路由条目可以是一个简单的字符串(处理器路径)或一个具有以下选项的对象:
| 选项 | 类型 | 描述 |
|---|---|---|
handler | string | 事件处理器文件或虚拟模块 ID 的路径 |
method | string | 要匹配的 HTTP 方法(get、post 等) |
lazy | boolean | 使用懒加载导入处理器 |
format | "web" | "node" | 处理器类型。"node" 处理器会被转换为兼容 web 的格式 |
env | string | string[] | 包含此处理器的环境("dev"、"prod"、"prerender" 或预设名称) |
handlers 配置
handlers 数组适用于注册具有路由匹配控制权的中间件:
import { defineNitroConfig } from "nitro/config";
export default defineNitroConfig({
handlers: [
{
route: "/api/**",
handler: "./server/middleware/api-auth.ts",
middleware: true,
},
],
});
每个处理器条目支持以下选项:
| 选项 | 类型 | 描述 |
|---|---|---|
route | string | HTTP 路径名模式(例如 /test、/api/:id、/blog/**) |
handler | string | 事件处理器文件或虚拟模块 ID 的路径 |
method | string | 要匹配的 HTTP 方法(get、post 等) |
middleware | boolean | 在路由处理器之前作为中间件运行处理器 |
lazy | boolean | 使用懒加载导入处理器 |
format | "web" | "node" | 处理器类型。"node" 处理器会被转换为兼容 web 的格式 |
env | string | string[] | 包含此处理器的环境("dev"、"prod"、"prerender" 或预设名称) |
中间件
Nitro 路由中间件可以介入请求生命周期。
在 middleware/ 目录中的中间件会自动注册。
middleware/
auth.ts
logger.ts
...
routes/
hello.ts
简单中间件
中间件的定义与路由处理器完全相同,唯一的区别是它们不应该返回任何内容。 从中间件返回的行为类似于从请求返回——该值将作为响应返回,后续代码将不会运行。
import { defineHandler } from "nitro";
export default defineHandler((event) => {
// 扩展或修改事件
event.context.user = { name: "Nitro" };
});
middleware/ 目录中的中间件会自动注册到所有路由。如果你想为特定路由注册中间件,请参阅 对象语法事件处理器。
路由元数据
你可以在事件处理器文件中使用 defineRouteMeta 宏在构建时定义路由处理器元数据。
import { defineRouteMeta } from "nitro";
import { defineHandler } from "nitro";
defineRouteMeta({
openAPI: {
tags: ["test"],
description: "测试路由描述",
parameters: [{ in: "query", name: "test", required: true }],
},
});
export default defineHandler(() => "OK");
执行顺序
中间件按目录列表顺序执行。
middleware/
auth.ts <-- 第一个
logger.ts <-- 第二个
... <-- 第三个
在中间件文件名前添加数字以控制它们的执行顺序。
middleware/
1.logger.ts <-- 第一个
2.auth.ts <-- 第二个
3.... <-- 第三个
1.filename.ts、2.filename.ts 和 10.filename.ts,10.filename.ts 会排在 1.filename.ts 之后。为了避免这种情况,如果在同一目录中有超过 10 个中间件,请在 1-9 前添加 0,如 01。请求过滤
中间件在每个请求上都会执行。
应用自定义逻辑将它们限定在特定条件下。
例如,你可以使用 URL 将中间件应用于特定路由:
import { defineHandler } from "nitro";
export default defineHandler((event) => {
// 仅对 /auth 路由执行
if (event.url.pathname.startsWith('/auth')) {
event.context.user = { name: "Nitro" };
}
});
路由作用域中间件
你可以使用 handlers 配置并设置 middleware 选项和特定的 route 来为特定路由模式注册中间件:
import { defineNitroConfig } from "nitro/config";
export default defineNitroConfig({
handlers: [
{
route: "/api/**",
handler: "./server/middleware/api-auth.ts",
middleware: true,
},
],
});
与全局中间件(在 middleware/ 目录中注册,匹配 /**)不同,路由作用域中间件仅对匹配指定模式的请求运行。
错误处理
你可以在路由和中间件中使用 H3 提供的工具 来处理错误。
错误返回给客户端的方式取决于环境。在开发环境中,带有 Accept 请求头为 text/html(如浏览器)的请求将收到 HTML 错误页面。在生产环境中,错误始终以 JSON 格式发送。
此行为可以通过某些请求属性(例如:Accept 或 User-Agent 请求头)来覆盖。
代码分割
Nitro 为每个路由处理程序创建单独的代码块。代码块在首次请求时按需加载,因此 /api/users 不会加载 /api/posts 的代码。
查看 inlineDynamicImports 以将所有内容打包到单个文件中。
路由规则
Nitro 允许你在配置中为每个路由添加顶层逻辑。可用于重定向、代理、缓存、认证以及为路由添加请求头。
这是一个从路由模式(遵循 rou3)到路由选项的映射。
当设置了 cache 选项时,匹配模式的处理程序将自动使用 defineCachedEventHandler 包裹。查看 缓存指南 以了解有关此函数的更多信息。
swr: true|number 是 cache: { swr: true, maxAge: number } 的简写你可以在 nitro.routeRules 选项中设置路由规则。
import { defineConfig } from "nitro";
export default defineNitroConfig({
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 来禁用由更通用模式设置的规则:
import { defineNitroConfig } from "nitro/config";
export default defineNitroConfig({
routeRules: {
'/api/cached/**': { swr: true },
'/api/cached/no-cache': { cache: false, swr: false },
'/admin/**': { basicAuth: { username: 'admin', password: 'secret' } },
'/admin/public/**': { basicAuth: false },
}
});
请求头
为匹配的路由设置自定义响应头:
import { defineNitroConfig } from "nitro/config";
export default defineNitroConfig({
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 请求头:
import { defineNitroConfig } from "nitro/config";
export default defineNitroConfig({
routeRules: {
'/api/v1/**': {
cors: true,
headers: { 'access-control-allow-methods': 'GET' },
},
}
});
重定向
将匹配的路由重定向到另一个 URL。使用字符串进行简单重定向(默认为 307 状态码),或使用对象进行更精细的控制:
import { defineNitroConfig } from "nitro/config";
export default defineNitroConfig({
routeRules: {
// 简单重定向(307 状态码)
'/old-page': { redirect: '/new-page' },
// 自定义状态码的重定向
'/legacy': { redirect: { to: 'https://example.com/', status: 308 } },
// 通配符重定向 — 保留模式后的路径
'/old-blog/**': { redirect: 'https://blog.example.com/**' },
}
});
代理
将请求代理到另一个 URL。支持内部和外部目标:
import { defineNitroConfig } from "nitro/config";
export default defineNitroConfig({
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 基础认证保护路由:
import { defineNitroConfig } from "nitro/config";
export default defineNitroConfig({
routeRules: {
'/admin/**': {
basicAuth: {
username: 'admin',
password: 'supersecret',
realm: '管理区域', // 可选,显示在浏览器提示框中
},
},
// 为子路径禁用基础认证
'/admin/public/**': { basicAuth: false },
}
});
缓存(SWR / 静态)
使用 cache、swr 或 static 选项控制缓存行为:
import { defineNitroConfig } from "nitro/config";
export default defineNitroConfig({
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: true 是 cache: { swr: true } 的简写,swr: <number> 是 cache: { swr: true, maxAge: <number> } 的简写。预渲染
标记路由以在构建时进行预渲染:
import { defineNitroConfig } from "nitro/config";
export default defineNitroConfig({
routeRules: {
'/about': { prerender: true },
'/dynamic/**': { prerender: false },
}
});
ISR (Vercel)
为 Vercel 部署配置增量静态再生:
import { defineNitroConfig } from "nitro/config";
export default defineNitroConfig({
routeRules: {
'/isr/**': { isr: true },
'/isr-ttl/**': { isr: 60 },
'/isr-custom/**': {
isr: {
expiration: 60,
allowQuery: ['q'],
group: 1,
},
},
}
});
路由规则参考
| 选项 | 类型 | 描述 |
|---|---|---|
headers | Record<string, string> | 自定义响应头 |
redirect | string | { to: string, status?: number } | 重定向到另一个 URL(默认状态码:307) |
proxy | string | { to: string, ...proxyOptions } | 将请求代理到另一个 URL |
cors | boolean | 启用宽松的 CORS 请求头 |
cache | object | false | 缓存选项(参见 缓存指南) |
swr | boolean | number | cache: { swr: true, maxAge: number } 的简写 |
static | boolean | number | 静态缓存的简写 |
basicAuth | { username, password, realm? } | false | HTTP 基础认证 |
prerender | boolean | 启用/禁用预渲染 |
isr | boolean | number | object | 增量静态再生(Vercel) |
运行时路由规则
路由规则可以通过 runtimeConfig 提供,允许通过环境变量覆盖而无需重新构建:
import { defineNitroConfig } from "nitro/config";
export default defineNitroConfig({
runtimeConfig: {
nitro: {
routeRules: {
'/api/**': { headers: { 'x-env': 'production' } },
},
},
},
});
配置参考
这些配置选项控制路由行为:
| 选项 | 类型 | 默认值 | 描述 |
|---|---|---|---|
baseURL | string | "/" | 所有路由的基础 URL |
apiBaseURL | string | "/api" | api/ 目录中路由的基础 URL |
apiDir | string | "api" | API 路由的目录名称 |
routesDir | string | "routes" | 基于文件的路由的目录名称 |
serverDir | string | false | false | 用于扫描路由、中间件、插件等的服务器目录 |
scanDirs | string[] | [] | 扫描路由的额外目录 |
routes | Record<string, string | handler> | {} | 路由到处理程序的映射 |
handlers | NitroEventHandler[] | [] | 程序化处理程序注册(主要用于中间件) |
routeRules | Record<string, NitroRouteConfig> | {} | 匹配模式的路由规则 |
ignore | string[] | [] | 文件扫描期间忽略的 glob 模式 |