服务器路由
事件处理器
事件处理器 是一个功能,它将绑定到一个路由,并在路由被路由器匹配到一个输入请求时执行。
文件系统路由
Nitro 支持基于文件的 API 路由(文件自动映射到 h3 路由)。定义一个路由只需要在 api/
或 routes/
目录中创建一个文件。
每个文件只能定义一个处理程序,你可以 将 HTTP 方法附加 到文件名,以定义一个特定的请求方法。
api/
test.ts <-- /api/test
routes/
hello.get.ts <-- GET /hello
hello.post.ts <-- POST /hello
nitro.config.ts
你可以通过创建子目录来嵌套路由。
routes/
communities/
index.get.ts
index.post.ts
[id]/
index.get.ts
index.post.ts
hello.get.ts
hello.post.ts
api/
目录作为特性,因此放置在 /api
中的路由将无法工作。
你必须使用 routes/api/
。简单路由
首先,在 routes/
或 api/
目录中创建一个文件。文件名将成为路由路径。
然后,导出一个用 defineEventHandler
包装的函数,当路由匹配时将被执行。
export default defineEventHandler(() => {
return { hello: 'API' }
})
带参数的路由
单个参数
要定义具有参数的路由,请使用 [<param>]
语法,其中 <param>
是参数的名称。该参数将可在 event.context.params
对象中使用,或使用来自 unjs/h3 的 getRouterParam
工具。
export default defineEventHandler(event => {
const name = getRouterParam(event, 'name')
return `Hello ${name}!`
})
调用带参数的路由 /hello/nitro
,你将得到:
Hello nitro!
多个参数
你可以使用 [<param1>]/[<param2>]
语法在一个路由中定义多个参数,其中每个参数是一个文件夹。你 不能 在单个文件名或文件夹中定义多个参数。
export default defineEventHandler(event => {
const name = getRouterParam(event, 'name')
const age = getRouterParam(event, 'age')
return `Hello ${name}! You are ${age} years old.`
})
捕获所有参数
你可以使用 [...<param>]
语法捕获 URL 的所有剩余部分。这将包括参数中的 /
。
export default defineEventHandler(event => {
const name = getRouterParam(event, 'name')
return `Hello ${name}!`
})
调用带参数的路由 /hello/nitro/is/hot
,你将得到:
Hello nitro/is/hot!
特定请求方法
你可以将 HTTP 方法附加到文件名,以强制路由仅匹配特定的 HTTP 请求方法,例如 hello.get.ts
只会匹配 GET
请求。你可以使用任何你想要的 HTTP 方法。
// routes/users/[id].get.ts
export default defineEventHandler(async (event) => {
const id = getRouterParam(event, 'id')
// 做一些与 id 相关的操作
return `User profile!`
})
捕获所有路由
你可以创建一个特殊的路由,匹配所有未被任何其他路由匹配的路由。这对于创建默认路由很有用。
要创建捕获所有路由,在 routes/
或 api/
目录中或任何子目录中创建一个名为 [...].ts
的文件。
export default defineEventHandler(event => {
const url = getRequestURL(event)
return `Hello ${url}!`
})
环境特定处理程序
你可以通过在文件名后添加 .dev
、.prod
或 .prerender
后缀,指定仅在特定构建中包含的路由,例如:routes/test.get.dev.ts
或 routes/test.get.prod.ts
。
handlers[]
配置的编程注册路径,指定多个环境或使用预设名称作为环境。中间件
Nitro 路由中间件可以钩入请求生命周期。
中间件在 middleware/
目录内自动注册。
routes/
hello.ts
middleware/
auth.ts
logger.ts
...
nitro.config.ts
简单中间件
中间件的定义与路由处理程序完全相同,唯一的例外是在于它们不应返回任何内容。 从中间件返回的内容会像从请求返回一样 - 返回的值将作为响应返回,后续代码将不再运行。
export default defineEventHandler((event) => {
// 扩展或修改事件
event.context.user = { name: 'Nitro' }
})
在 middleware/
目录中的中间件会自动注册到所有路由。如果你想为特定路由注册中间件,请参见 对象语法事件处理程序。
路由元信息
你可以在构建时通过 defineRouteMeta
微功能在事件处理程序文件中定义路由处理程序元信息。
defineRouteMeta({
openAPI: {
tags: ["test"],
description: "Test route description",
parameters: [{ in: "query", name: "test", required: true }],
},
});
export default defineEventHandler(() => "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 为特定路由应用中间件:
export default defineEventHandler((event) => {
// 仅在 /auth 路由执行
if (getRequestURL(event).pathname.startsWith('/auth')) {
event.context.user = { name: 'Nitro' }
}
})
Error handling
You can use the utilities available in H3 to handle errors in both routes and middlewares.
The way errors are sent back to the client depends on the route's path. For most routes Content-Type
is set to text/html
by default and a simple html error page is delievered. If the route starts with /api/
(either because it is placed in api/
or routes/api/
) the default will change to application/json
and a JSON object will be sent.
This behaviour can be overridden by some request properties (e.g.: Accept
or User-Agent
headers).
路由规则
Nitro 允许你在配置的顶层为每个路由添加逻辑。它可以用于重定向、代理、缓存和向路由添加头信息。
它是从路由模式(遵循 unjs/radix3)到路由选项的映射。
当设置 cache
选项时,匹配模式的处理程序将自动包裹在 defineCachedEventHandler
中。请参见 缓存指南 以了解有关此功能的更多信息。
swr: true|number
是 cache: { swr: true, maxAge: number }
的简写。你可以使用 routeRules
选项在 nitro.config.ts
中设置路由规则。
export default defineNitroConfig({
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/**' },
}
})