server
Nuxt 会自动扫描这些目录中的文件,以注册支持热模块替换 (HMR) 的 API 和服务器处理程序。
¥Nuxt automatically scans files inside these directories to register API and server handlers with Hot Module Replacement (HMR) support.
-| server/
---| api/
-----| hello.ts # /api/hello
---| routes/
-----| bonjour.ts # /bonjour
---| middleware/
-----| log.ts # log all requests
每个文件都应导出一个用 defineEventHandler()
或 eventHandler()
(别名)定义的默认函数。
¥Each file should export a default function defined with defineEventHandler()
or eventHandler()
(alias).
处理程序可以直接返回 JSON 数据、Promise
或使用 event.node.res.end()
发送响应。
¥The handler can directly return JSON data, a Promise
, or use event.node.res.end()
to send a response.
export default defineEventHandler((event) => {
return {
hello: 'world'
}
})
现在,你可以在页面和组件中通用地调用此 API:
¥You can now universally call this API in your pages and components:
<script setup lang="ts">
const { data } = await useFetch('/api/hello')
</script>
<template>
<pre>{{ data }}</pre>
</template>
服务器路由
¥Server Routes
~/server/api
中的文件在其路由中会自动添加 /api
前缀。
¥Files inside the ~/server/api
are automatically prefixed with /api
in their route.
要添加不带 /api
前缀的服务器路由,请将其放入 ~/server/routes
目录中。
¥To add server routes without /api
prefix, put them into ~/server/routes
directory.
示例:
¥Example:
export default defineEventHandler(() => 'Hello World!')
根据上述示例,你可以通过 /hello
对象访问组件内的 group/id:
¥Given the example above, the /hello
route will be accessible at http://localhost:3000/hello.
服务器中间件
¥Server Middleware
Nuxt 将自动读取 ~/server/middleware
中的任何文件,为你的项目创建服务器中间件。
¥Nuxt will automatically read in any file in the ~/server/middleware
to create server middleware for your project.
中间件处理程序将在任何其他服务器路由之前在每个请求上运行,以添加或检查标头、记录请求或扩展事件的请求对象。
¥Middleware handlers will run on every request before any other server route to add or check headers, log requests, or extend the event's request object.
示例:
¥Examples:
export default defineEventHandler((event) => {
console.log('New request: ' + getRequestURL(event))
})
export default defineEventHandler((event) => {
event.context.auth = { user: 123 }
})
服务器插件
¥Server Plugins
Nuxt 将自动读取 ~/server/plugins
目录中的所有文件并将其注册为 Nitro 插件。这允许扩展 Nitro 的运行时行为并挂接到生命周期事件。
¥Nuxt will automatically read any files in the ~/server/plugins
directory and register them as Nitro plugins. This allows extending Nitro's runtime behavior and hooking into lifecycle events.
示例:
¥Example:
export default defineNitroPlugin((nitroApp) => {
console.log('Nitro plugin', nitroApp)
})
服务器实用程序
¥Server Utilities
服务器路由由 unjs/h3 提供支持,它附带一组方便的辅助函数。
¥Server routes are powered by unjs/h3 which comes with a handy set of helpers.
你可以在 ~/server/utils
目录中自行添加更多助手。
¥You can add more helpers yourself inside the ~/server/utils
directory.
例如,你可以定义一个自定义处理程序实用程序,它封装原始处理程序并在返回最终响应之前执行其他操作。
¥For example, you can define a custom handler utility that wraps the original handler and performs additional operations before returning the final response.
示例:
¥Example:
import type { EventHandler, EventHandlerRequest } from 'h3'
export const defineWrappedResponseHandler = <T extends EventHandlerRequest, D> (
handler: EventHandler<T, D>
): EventHandler<T, D> =>
defineEventHandler<T>(async event => {
try {
// do something before the route handler
const response = await handler(event)
// do something after the route handler
return { response }
} catch (err) {
// Error handling
return { err }
}
})
服务器类型
¥Server Types
为了提高 IDE 中 'nitro' 和 'vue' 自动导入之间的清晰度,你可以添加一个包含以下内容的 ~/server/tsconfig.json
:
¥To improve clarity within your IDE between the auto-imports from 'nitro' and 'vue', you can add a ~/server/tsconfig.json
with the following content:
{
"extends": "../.nuxt/tsconfig.server.json"
}
目前,这些值在类型检查(nuxi typecheck
)时不会被考虑,但你应该在 IDE 中获得更好的类型提示。
¥Currently, these values won't be respected when type checking (nuxi typecheck
), but you should get better type hints in your IDE.
Recipes
路由参数
¥Route Parameters
服务器路由可以在文件名的括号中使用动态参数,例如 /api/hello/[name].ts
,并通过 event.context.params
访问。
¥Server routes can use dynamic parameters within brackets in the file name like /api/hello/[name].ts
and be accessed via event.context.params
.
export default defineEventHandler((event) => {
const name = getRouterParam(event, 'name')
return `Hello, ${name}!`
})
getValidatedRouterParams
与模式验证器(例如 Zod)一起使用,以确保运行时和类型安全。¥Alternatively, use getValidatedRouterParams
with a schema validator such as Zod for runtime and type safety.现在,你可以在 /api/hello/nuxt
上通用地调用此 API 并获取 Hello, nuxt!
。
¥You can now universally call this API on /api/hello/nuxt
and get Hello, nuxt!
.
匹配 HTTP 方法
¥Matching HTTP Method
处理程序可以直接返回对象/数组,以自动处理 JSON 响应。以匹配请求的 HTTP 方法。
¥Handle file names can be suffixed with .get
, .post
, .put
, .delete
, ... to match request's HTTP Method.
export default defineEventHandler(() => 'Test get handler')
export default defineEventHandler(() => 'Test post handler')
根据上述示例,/test
路由将在 上可访问。
¥Given the example above, fetching /test
with:
- GET 方法:返回
Test get handler
- POST 方法:返回
Test post handler
- 任何其他方法:返回 405 错误
你还可以在目录中使用 index.[method].ts
来以不同的方式构建代码,这对于创建 API 命名空间非常有用。
¥You can also use index.[method].ts
inside a directory for structuring your code differently, this is useful to create API namespaces.
export default defineEventHandler((event) => {
// handle GET requests for the `api/foo` endpoint
})
export default defineEventHandler((event) => {
// handle POST requests for the `api/foo` endpoint
})
export default defineEventHandler((event) => {
// handle GET requests for the `api/foo/bar` endpoint
})
Catch-all 路由
¥Catch-all Route
捕获所有路由有助于回退路由处理。
¥Catch-all routes are helpful for fallback route handling.
例如,创建一个名为 ~/server/api/foo/[...].ts
的文件将为所有不匹配任何路由处理程序(例如 /api/foo/bar/baz
)的请求注册一个 catch-all 路由。
¥For example, creating a file named ~/server/api/foo/[...].ts
will register a catch-all route for all requests that do not match any route handler, such as /api/foo/bar/baz
.
export default defineEventHandler((event) => {
// event.context.path to get the route path: '/api/foo/bar/baz'
// event.context.params._ to get the route segment: 'bar/baz'
return `Default foo handler`
})
你可以使用 ~/server/api/foo/[...slug].ts
为 catch-all 路由设置名称,并通过 event.context.params.slug
访问它。
¥You can set a name for the catch-all route by using ~/server/api/foo/[...slug].ts
and access it via event.context.params.slug
.
export default defineEventHandler((event) => {
// event.context.params.slug to get the route segment: 'bar/baz'
return `Default foo handler`
})
Body 处理
¥Body Handling
export default defineEventHandler(async (event) => {
const body = await readBody(event)
return { body }
})
readValidatedBody
与模式验证器(例如 Zod)一起使用,以确保运行时和类型安全。¥Alternatively, use readValidatedBody
with a schema validator such as Zod for runtime and type safety.现在你可以使用以下方式普遍调用此 API:
¥You can now universally call this API using:
<script setup lang="ts">
async function submit() {
const { body } = await $fetch('/api/submit', {
method: 'post',
body: { test: 123 }
})
}
</script>
submit.post.ts
仅用于匹配使用 POST
方法且可以接受请求正文的请求。在 GET 请求中使用 readBody
时,readBody
将抛出 405 Method Not Allowed
HTTP 错误。查询参数
¥Query Parameters
示例查询 /api/query?foo=bar&baz=qux
¥Sample query /api/query?foo=bar&baz=qux
export default defineEventHandler((event) => {
const query = getQuery(event)
return { a: query.foo, b: query.baz }
})
getValidatedQuery
与模式验证器(例如 Zod)一起使用,以确保运行时和类型安全。¥Alternatively, use getValidatedQuery
with a schema validator such as Zod for runtime and type safety.错误处理
¥Error Handling
如果没有抛出错误,则返回状态码 200 OK
。
¥If no errors are thrown, a status code of 200 OK
will be returned.
任何未捕获的错误都将返回 500 Internal Server Error
HTTP 错误。
¥Any uncaught errors will return a 500 Internal Server Error
HTTP Error.
要返回其他错误代码,请使用 createError
抛出异常:
¥To return other error codes, throw an exception with createError
:
export default defineEventHandler((event) => {
const id = parseInt(event.context.params.id) as number
if (!Number.isInteger(id)) {
throw createError({
statusCode: 400,
statusMessage: 'ID should be an integer',
})
}
return 'All good'
})
状态码
¥Status Codes
要返回其他状态代码,请使用 setResponseStatus
实用程序。
¥To return other status codes, use the setResponseStatus
utility.
例如,要返回 202 Accepted
¥For example, to return 202 Accepted
export default defineEventHandler((event) => {
setResponseStatus(event, 202)
})
运行时配置
¥Runtime Config
export default defineEventHandler(async (event) => {
const config = useRuntimeConfig(event)
const repo = await $fetch('https://api.github.com/repos/nuxt/nuxt', {
headers: {
Authorization: `token ${config.githubToken}`
}
})
return repo
})
export default defineNuxtConfig({
runtimeConfig: {
githubToken: ''
}
})
NUXT_GITHUB_TOKEN='<my-super-token>'
请求 Cookies
¥Request Cookies
export default defineEventHandler((event) => {
const cookies = parseCookies(event)
return { cookies }
})
转发上下文和标头
¥Forwarding Context & Headers
默认情况下,在服务器路由中发出获取请求时,传入请求的标头和请求上下文都不会被转发。你可以使用 event.$fetch
在服务器路由中发出获取请求时转发请求上下文和标头。
¥By default, neither the headers from the incoming request nor the request context are forwarded when
making fetch requests in server routes. You can use event.$fetch
to forward the request context and headers when making fetch requests in server routes.
export default defineEventHandler((event) => {
return event.$fetch('/api/forwarded')
})
transfer-encoding
、connection
、keep-alive
、upgrade
、expect
、host
、accept
响应后等待 Promises
¥Awaiting Promises After Response
处理服务器请求时,你可能需要执行不会阻塞客户端响应的异步任务(例如,缓存和日志记录)。你可以使用 event.waitUntil
在后台等待 Promise,而不会延迟响应。
¥When handling server requests, you might need to perform asynchronous tasks that shouldn't block the response to the client (for example, caching and logging). You can use event.waitUntil
to await a promise in the background without delaying the response.
event.waitUntil
方法接受一个承诺,该承诺将在处理程序终止前等待,从而确保任务完成,即使服务器在发送响应后立即终止处理程序。它与运行时提供程序集成,以利用其原生功能在发送响应后处理异步操作。
¥The event.waitUntil
method accepts a promise that will be awaited before the handler terminates, ensuring the task is completed even if the server would otherwise terminate the handler right after the response is sent. This integrates with runtime providers to leverage their native capabilities for handling asynchronous operations after the response is sent.
const timeConsumingBackgroundTask = async () => {
await new Promise((resolve) => setTimeout(resolve, 1000))
};
export default eventHandler((event) => {
// schedule a background task without blocking the response
event.waitUntil(timeConsumingBackgroundTask())
// immediately send the response to the client
return 'done'
});
高级用法
¥Advanced Usage
Nitro 配置
¥Nitro Config
你可以在 nuxt.config
中使用 nitro
键直接设置 Nitro 配置。
¥You can use nitro
key in nuxt.config
to directly set Nitro configuration.
export default defineNuxtConfig({
// https://nitro.unjs.io/config
nitro: {}
})
嵌套路由
¥Nested Router
import { createRouter, defineEventHandler, useBase } from 'h3'
const router = createRouter()
router.get('/test', defineEventHandler(() => 'Hello World'))
export default useBase('/api/hello', router.handler)
发送流
¥Sending Streams
import fs from 'node:fs'
import { sendStream } from 'h3'
export default defineEventHandler((event) => {
return sendStream(event, fs.createReadStream('/path/to/file'))
})
发送重定向
¥Sending Redirect
export default defineEventHandler(async (event) => {
await sendRedirect(event, '/path/redirect/to', 302)
})
旧版处理程序或中间件
¥Legacy Handler or Middleware
export default fromNodeMiddleware((req, res) => {
res.end('Legacy handler')
})
export default fromNodeMiddleware((req, res, next) => {
console.log('Legacy middleware')
next()
})
next()
回调与 async
或返回 Promise
的旧式中间件结合使用。¥Never combine next()
callback with a legacy middleware that is async
or returns a Promise
.服务器存储
¥Server Storage
Nitro 提供跨平台的 存储层。为了配置额外的存储挂载点,你可以使用 nitro.storage
或 服务器插件。
¥Nitro provides a cross-platform storage layer. In order to configure additional storage mount points, you can use nitro.storage
, or server plugins.
添加 Redis 存储的示例:
¥Example of adding a Redis storage:
使用 nitro.storage
:
¥Using nitro.storage
:
export default defineNuxtConfig({
nitro: {
storage: {
redis: {
driver: 'redis',
/* redis connector options */
port: 6379, // Redis port
host: "127.0.0.1", // Redis host
username: "", // needs Redis >= 6
password: "",
db: 0, // Defaults to 0
tls: {} // tls/ssl
}
}
}
})
然后在你的 API 处理程序中:
¥Then in your API handler:
export default defineEventHandler(async (event) => {
// List all keys with
const keys = await useStorage('redis').getKeys()
// Set a key with
await useStorage('redis').setItem('foo', 'bar')
// Remove a key with
await useStorage('redis').removeItem('foo')
return {}
})
:
阅读更多关于 Nitro 存储层的内容。
¥Read more about Nitro Storage Layer.
::
或者,你可以使用服务器插件和运行时配置创建存储挂载点:
¥Alternatively, you can create a storage mount point using a server plugin and runtime config:
import redisDriver from 'unstorage/drivers/redis'
export default defineNitroPlugin(() => {
const storage = useStorage()
// Dynamically pass in credentials from runtime configuration, or other sources
const driver = redisDriver({
base: 'redis',
host: useRuntimeConfig().redis.host,
port: useRuntimeConfig().redis.port,
/* other redis connector options */
})
// Mount driver
storage.mount('redis', driver)
})
export default defineNuxtConfig({
runtimeConfig: {
redis: { // Default values
host: '',
port: 0,
/* other redis connector options */
}
}
})