Guide

服务器路由


¥Server Routes

Nitro 支持文件系统路由,可自动将文件映射到 H3 路由。

事件处理程序

¥Event handlers

事件处理程序 是一个函数,它将绑定到路由,并在路由与传入请求匹配时执行。

¥An event handler is a function that will be bound to a route and executed when the route is matched by the router for an incoming request.

Read more in h3.unjs.io/guide/event-handler.

文件系统路由

¥Filesystem routing

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

¥Nitro supports file-based routing for your API routes (files are automatically mapped to h3 routes). Defining a route is as simple as creating a file inside the server/api/ or server/routes/ directory.

每个文件只能定义一个处理程序,并且你可以将 附加 HTTP 方法 添加到文件名以定义特定的请求方法。

¥You can only define one handler per files and you can append the HTTP method to the filename to define a specific request method.

server/
  api/
    test.ts      <-- /api/test
  routes/
    hello.get.ts     <-- GET /hello
    hello.post.ts    <-- POST /hello
nitro.config.ts

你可以通过创建子目录来嵌套路由。

¥You can nest routes by creating subdirectories.

server/
  routes/
    communities/
      index.get.ts
      index.post.ts
      [id]/
        index.get.ts
        index.post.ts
    hello.get.ts
    hello.post.ts
某些提供商(例如 Vercel)使用顶层 /api/ 目录作为功能,因此放置在 /api 中的路由将无法工作。你必须使用 server/routes/api/

简单路由

¥Simple routes

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

¥First, create a file in server/routes/ or server/api/ directory. The filename will be the route path.

然后,导出一个封装在 defineEventHandler 中的函数,该函数将在路由匹配时执行。

¥Then, export a function wrapped in defineEventHandler that will be executed when the route is matched.

server/api/test.ts
export default defineEventHandler(() => {
  return { hello: 'API' }
})

带参数的路由

¥Route with params

单个参数

¥Single param

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

¥To define a route with params, use the [<param>] syntax where <param> is the name of the param. The param will be available in the event.context.params object or using the getRouterParam utility from unjs/h3.

server/routes/hello/[name].ts
export default defineEventHandler(event => {
  const name = getRouterParam(event, 'name')

  return `Hello ${name}!`
})

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

¥Call the route with the param /hello/nitro, you will get:

Response
Hello nitro!

多个参数

¥Multiple params

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

¥You can define multiple params in a route using [<param1>]/[<param2>] syntax where each param is a folder. You cannot define multiple params in a single filename of folder.

server/routes/hello/[name]/[age].ts
export default defineEventHandler(event => {
  const name = getRouterParam(event, 'name')
  const age = getRouterParam(event, 'age')

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

捕获所有参数

¥Catch all params

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

¥You can capture all the remaining parts of a URL using [...<param>] syntax. This will include the / in the param.

server/routes/hello/[...name].ts
export default defineEventHandler(event => {
  const name = getRouterParam(event, 'name')

  return `Hello ${name}!`
})

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

¥Call the route with the param /hello/nitro/is/hot, you will get:

Response
Hello nitro/is/hot!

特定请求方法

¥Specific request method

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

¥You can append the HTTP method to the filename to force the route to be matched only for a specific HTTP request method, for example hello.get.ts will only match for GET requests. You can use any HTTP method you want.

// server/routes/users/[id].get.ts
export default defineEventHandler(async (event) => {
  const id = getRouterParam(event, 'id')

  // Do something with id

  return `User profile!`
})

捕获所有路由

¥Catch all route

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

¥You can create a special route that will match all routes that are not matched by any other route. This is useful for creating a default route.

要创建捕获所有事件的路由,请在 server/routes/server/api/ 目录或任何子目录中创建一个名为 [...].ts 的文件。

¥To create a catch all route, create a file named [...].ts in the server/routes/ or server/api/ directory or in any subdirectory.

server/routes/[...].ts
export default defineEventHandler(event => {
  const url = getRequestURL(event)

  return `Hello ${url}!`
})

特定于环境的处理程序

¥Environment specific handlers

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

¥You can specify for a route that will only be included in specific builds by adding a .dev, .prod or .prerender suffix to the file name, for example: routes/test.get.dev.ts or routes/test.get.prod.ts.

你可以通过 handlers[] 配置以编程方式注册路由来指定多个环境或指定一个预设名称作为环境。

中间件

¥Middleware

Nitro 路由中间件可以连接到请求生命周期。

¥Nitro route middleware can hook into the request lifecycle.

中间件可以在请求处理之前修改请求,而不是处理之后。
Read more in h3.unjs.io/guide/event-handler#middleware.

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

¥Middleware are auto-registered within the server/middleware/ directory.

server/
  routes/
    hello.ts
  middleware/
    auth.ts
    logger.ts
    ...
nitro.config.ts

简单中间件

¥Simple middleware

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

¥Middleware are defined exactly like route handlers with the only exception that they should not return anything. Returning from middleware behaves like returning from a request - the value will be returned as a response and further code will not be ran.

server/middleware/auth.ts
export default defineEventHandler((event) => {
  // Extends or modify the event
  event.context.user = { name: 'Nitro' }
})

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

¥Middleware in server/middleware/ directory are automatically registered for all routes. If you want to register a middleware for a specific route, see Object Syntax Event Handler.

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

路由元数据

¥Route Meta

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

¥You can define route handler meta at build-time using defineRouteMeta macro in the event handler files.

🚧 此功能目前处于实验阶段。
server/api/test.ts
defineRouteMeta({
  openAPI: {
    tags: ["test"],
    description: "Test route description",
    parameters: [{ in: "query", name: "test", required: true }],
  },
});

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

执行顺序

¥Execution order

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

¥Middleware are executed in directory listing order.

server/
  middleware/
    auth.ts <-- First
    logger.ts <-- Second
    ... <-- Third

在中间件前添加数字以控制其执行顺序。

¥Prefix middleware with a number to control their execution order.

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

请求过滤

¥Request filtering

中间件会在每次请求时执行。

¥Middleware are executed on every request.

应用自定义逻辑,使其适用于特定条件。

¥Apply custom logic to scope them to specific conditions.

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

¥For example, you can use the URL to apply a middleware to a specific route:

server/middleware/auth.ts
export default defineEventHandler((event) => {
  // Will only execute for /auth route
  if (getRequestURL(event).pathname.startsWith('/auth')) {
    event.context.user = { name: 'Nitro' }
  }
})

错误处理

¥Error handling

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

¥You can use the utilities available in H3 to handle errors in both routes and middlewares.

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

¥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 delivered. 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.

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

¥This behaviour can be overridden by some request properties (e.g.: Accept or User-Agent headers).

路由规则

¥Route Rules

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

¥Nitro allows you to add logic at the top-level for each route of your configuration. It can be used for redirecting, proxying, caching and adding headers to routes.

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

¥It is a map from route pattern (following unjs/radix3) to route options.

设置 cache 选项后,匹配模式的处理程序将自动使用 defineCachedEventHandler 进行封装。请参阅 缓存指南 了解有关此功能的更多信息。

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

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

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

¥You can set route rules in nitro.config.ts using the routeRules option.

export default defineNitroConfig({
  routeRules: {
    '/blog/**': { swr: true },
    '/blog/**': { swr: 600 },
    '/blog/**': { static: true },
    '/blog/**': { cache: { /* cache options*/ } },
    '/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/**' },
  }
})