服务器导入
Nuxt 可以搭配不同的服务器构建器使用,可以选择 Nitro 3(nitro,搭配 Nuxt 5+)、Nitro 2(nitropack,搭配 Nuxt 3/4),或直接使用 Vite。
nuxt/server 为不依赖特定服务器运行时的服务器代码提供通用工具。它是 Nuxt 的第二个运行时接口,与 nuxt/app(也可通过 #app 访问)并列,后者用于应用中也会在浏览器里运行的部分。
import { defineEventHandler, getQuery } from 'nuxt/server'
export default defineEventHandler((event) => {
const { name } = getQuery<{ name?: string }>(event)
return { message: `Hello, ${name ?? 'world'}!` }
})这段代码可以在 @nuxt/nitro-server 和 @nuxt/vite-server 下运行,也能在 h3 或 Nitro 升级主要版本后继续运行,因为 Nuxt 会集中处理这些变化。
nuxt/server 从 Nuxt 4.6 开始提供,因此同一个文件可以供运行 nitropack v2 的 Nuxt 4.6、运行 Nitro v3 的 Nuxt 5,以及未来构建器带来的任何环境使用。
nuxt,因此 nuxt/server 无需别名或额外依赖即可解析。导入它的模块不需要将 h3 或 Nitro 声明为对等依赖。类型和工具
| 导入 | 用途 |
|---|---|
defineEventHandler | 定义请求处理程序。 |
createError、isNuxtError | 创建并识别 HTTP 错误。 |
getRequestURL、getRequestHost、getRequestProtocol | 获取请求的 URL、主机和协议。仅在你控制且会覆盖这些请求头的代理之后,才传入 { xForwardedHost: true, xForwardedProto: true } 来信任对应的转发标头。 |
getRequestHeader、getRequestHeaders | 读取请求标头。 |
getRouterParam、getRouterParams | 读取与请求匹配的动态路径段。 |
getRequestIP | 获取客户端 IP 地址,请求中会信任转发标头。 |
getQuery、getValidatedQuery | 读取查询字符串,可选择进行校验。 |
readBody、readValidatedBody | 读取并解析请求体,可选择进行校验。 |
getCookie、parseCookies、setCookie、deleteCookie | 读取单个或全部 Cookie,以及写入 Cookie。 |
setResponseStatus | 设置响应状态和原因短语。 |
handleCors | 应用 CORS 标头并响应预检请求。 |
sendRedirect | 重定向请求。 |
serverFetch | 在进程内获取应用的路由,路径相对于 app.baseURL,并转发 cookie 和 authorization 标头(除非设置 forwardHeaders)。在不支持进程内 fetch 的服务器构建器上会拒绝。 |
useSession、getSession、updateSession、clearSession | 读取和写入密封的会话 Cookie。 |
deriveSecret | 从 appSecret 派生用途专属的密钥。 |
getRouteRules、matchRouteRules | 获取请求匹配的路由规则,或获取其他路径匹配的规则。 |
useRuntimeConfig | 获取服务器的运行时配置。 |
useServerHooks | 获取服务器运行时钩子,包括 render:html 等渲染器钩子,以及 NuxtServerHooks 中声明的钩子。 |
useAppConfig | 获取应用配置;传入事件时,每个请求都会得到一份副本。 |
工具旁还导出了以下类型:RequestEvent、RequestEventContext、NuxtRequestEvent、EventHandler、AppRouteRules、ServerRoutes、CorsOptions、ValidateResult、NuxtError、NuxtErrorDetails、NuxtErrorJSON、NuxtErrorLike、Session、SessionConfig、SessionData、SessionEvent、SessionManager、SessionPassword 和 SessionUpdate。
除 useAppConfig 外,这些名称都会在服务器代码中自动导入,因此上面的导入语句是可选的。保留它可以确保文件在关闭服务器自动导入的项目中正常工作,也是模块应该采用的做法。
defineEventHandler 会保留处理程序的返回类型,而这正是路由的 $fetch 和 useFetch 调用以及对其调用 serverFetch 时的 response.json() 所需的类型。请为返回值添加类型注解,而不是为处理程序添加。事件
RequestEvent 是 nuxt/server 工具所操作的事件,包含请求、请求 URL、待发送的响应以及请求上下文。
interface RequestEvent {
readonly req: Request
url: URL
readonly res: { status?: number, statusText?: string, readonly headers: Headers }
readonly context: RequestEventContext
}要设置、读取、追加或移除响应标头,请直接使用 event.res.headers:它是标准的 Headers 对象。
Nitro 还会添加更多内容,例如 event.node、event.runtime 和 event.waitUntil(),但这四个核心属性适用于所有运行时,且无需使用辅助工具:
export default defineEventHandler(async (event) => {
const { id } = await event.req.json()
return { id, page: event.url.searchParams.get('page') }
})NuxtRequestEvent 是同一个请求,但采用配置的构建器所提供的形式;在 @nuxt/nitro-server 下,它就是 h3 的 H3Event。
处理程序
处理程序文件必须默认导出 nuxt/server 中 defineEventHandler 的返回值。裸函数或由 h3 的 defineEventHandler 包装的函数会接收服务器运行时自己的 event。
处理程序可以返回:
- 可序列化为 JSON 的值,将以 JSON 发送,并使用
event.res上设置的状态和标头 Response,使用其自身的状态发送。event.res.headers上设置的标头会添加到其中,并替换同名标头;set-cookie除外,它会追加ReadableStream,作为响应体流式传输
校验
readValidatedBody 和 getValidatedQuery 接受任何 Standard Schema(Zod、Valibot、ArkType 等),也接受返回已校验值的函数;返回 true 表示接受输入,返回 false 则表示拒绝输入。
import { defineEventHandler, readValidatedBody } from 'nuxt/server'
import { z } from 'zod'
export default defineEventHandler(async (event) => {
const user = await readValidatedBody(event, z.object({ name: z.string() }))
return { created: user.name }
})无效输入会被拒绝,并返回 400 错误,其 data.issues 会列出校验失败的内容。传入 onError 可以使用其他错误拒绝输入。
客户端 IP
getRequestIP(event) 会返回服务器运行时报告的连接地址;如果运行时没有报告地址,则返回 undefined。默认情况下不会信任任何转发标头,因为客户端可以在其中发送任意值。
如果你控制代理,可传入 { xForwardedFor: true },改为读取 X-Forwarded-For 的第一项。仅当代理会覆盖此标头时才这样做:如果代理只是追加内容,客户端发送的值仍会排在最前面。
会话
useSession 会读取请求的会话;如果没有可读取的会话,则会将新会话密封到 Cookie 中。数据使用 iron 密封,因此会存储在 Cookie 中,而不是服务器存储中;Cookie 默认使用 httpOnly、secure、sameSite: 'lax' 和 path: '/'。
import { defineEventHandler, useSession } from 'nuxt/server'
export default defineEventHandler(async (event) => {
const session = await useSession<{ visits: number }>(event)
await session.update(data => ({ visits: (data.visits ?? 0) + 1 }))
return { visits: session.data.visits }
})如果不传入 password,会话会使用从应用的 appSecret 派生的密钥进行密封,因此只需设置 NUXT_APP_SECRET。传入至少 32 个字符的 password,即可改用你自己的密钥进行密封。设置 maxAge(以秒为单位)可使 Cookie 和密封值过期;设置 name 可将 Cookie 名称从 nuxt-session 改为其他名称;设置 cookie 可覆盖任意 Cookie 属性。
每个请求只会解封一次会话,因此你可以在任意多个位置调用 getSession。updateSession 和 clearSession 是相同的操作,只是不需要管理器对象。
派生密钥
deriveSecret(purpose) 会从 appSecret 为特定用途解析密钥:长度为 32 字节,以十六进制编码;只要 appSecret 不变,该密钥就保持稳定;不同用途对应的密钥也各不相同。会话辅助工具会使用它;模块也应该使用它,而不是自行请求密钥。请根据密钥的所有者为用途命名空间。
import { deriveSecret } from 'nuxt/server'
const password = await deriveSecret('my-module:tokens')如果未设置 appSecret 或其长度不足 32 个字符,则会抛出一条指出 NUXT_APP_SECRET 的 500 错误。
import { useSession } from 'nitro/h3' 访问。它们是独立实现,不能与这些工具互换:它们默认使用 h3 而不是 nuxt-session 作为 Cookie 名称,使用自己的配置,而且其中一个工具签发的会话无法由另一个工具解封。iron-webcrypto 发布基于 AES-GCM 的密封方案后迁移到该方案。迁移时,现有会话会以旧格式读取,并在下次写入时重新密封为新格式,因此用户不会被登出。密封值不能与 h3 的 useSession 生成的值互换。超越接口范围
nuxt/server 并非 h3 的重新导出,因此如果你需要 h3 和 Nitro 提供的其他功能,例如服务器生命周期(definePlugin、defineErrorHandler 和 Nitro 应用钩子),就需要直接导入。
这些辅助工具大多可以直接接收事件:
import { defineEventHandler } from 'nuxt/server'
import { readMultipartFormData } from 'nitro/h3'
export default defineEventHandler(async (event) => {
const parts = await readMultipartFormData(event)
return { received: parts?.length ?? 0 }
})任何仅读取请求的 h3 辅助工具都可以这样使用,例如 readRawBody、readFormData、readMultipartFormData 和 assertMethod。
如果处理程序需要运行时自身的事件,例如调用 proxy、proxyRequest、fetchWithEvent 或 writeEarlyHints,或者读取 event.node、event.waitUntil() 或 event.runtime,请为该处理程序从 nitro/h3 导入 defineEventHandler:
import { defineEventHandler, proxyRequest } from 'nitro/h3'
export default defineEventHandler(event => proxyRequest(event, 'https://example.com'))Nitro 自身的 API 大多不需要传入事件:getRouteRules(method, pathname)、serverFetch()、defineCachedHandler()、useStorage()、useDatabase() 和任务。
一个文件可以同时从 nitro/* 和 nuxt/server 导入内容。这样它只能在 Nitro v3 上运行,因此模块应将其注册为 nitro3 变体。
不具备可移植性的内容
以下功能需要访问 nuxt/server 之外的内容,因为 Nuxt 无法为每种构建器都提供这些功能:
- 存储。
useStorage()来自nitro/storage,其背后的驱动配置也来自那里。 - 缓存。
defineCachedHandler()和defineCachedFunction()来自nitro/cache。如果要使用可在任何地方运行的缓存,请直接依赖缓存库。 - 服务器插件。
definePlugin()来自nitro。在插件中,来自nuxt/server的useServerHooks()会注册渲染器钩子(包括render:html)以及NuxtServerHooks中声明的钩子;Nitro 自身的request、response和error等钩子来自nitro/app中的useNitroHooks()。 - 任务。
defineTask()和runTask()来自nitro/task。 - 延迟处理程序。
lazyEventHandler()来自nitro/h3。
仅限服务器代码
在 Vue 组件、插件或 shared/ 目录中导入 nuxt/server 会导致构建失败,错误会提示你改用 #app、#imports、$fetch 和 useFetch。这些上下文中仍能解析其类型,这也是 $fetch 能知道服务器路由返回内容的原因。
nuxt/server 也只能在服务器构建器打包的代码中工作,因为构建器提供了它背后的运行时配置、应用配置、钩子和进程内 fetch。在 Nuxt 进程中运行的代码(例如 nuxt.config.ts、模块的 setup 或传给 addDevServerHandler 的函数)不具备这些内容,因此不要在那里导入 nuxt/server:例如,useRuntimeConfig() 和 useAppConfig() 会返回空对象。请改为读取 nuxt.options,并参阅开发服务器处理程序了解如何在模块中编写处理程序。
模块
运行时代码只从 nuxt/server 导入内容的模块,可在 v4.6 及之后版本的任意服务器构建器下运行,无需检查版本,也不依赖 h3 或 Nitro:
import { defineEventHandler, useRuntimeConfig } from 'nuxt/server'
export default defineEventHandler(() => ({
version: useRuntimeConfig().myModule.version,
}))nuxt/server 保留为外部依赖;Nuxt 构建时会将它解析为正确的服务器构建器工具。要支持 Nuxt 4.6 之前的版本还需要多做一步,因为这些项目没有可供解析的 nuxt/server。你可以同时注册可移植文件和当前发布的文件,Nuxt 会选择应用能够运行的那个文件。