Nuxt 3 如何使用 server routes 编写自定义 API 接口?

文章导读
Nuxt 3 提供的 server routes 功能,可以让项目快速搭建后端 API 接口,而无需单独启动一个 Express 或 Nitro 服务。如果你正在开发一个全栈应用,或者需要一个简单的后端代理层,又不想引入额外的框架,server routes 是一个合适的选择。下面从场景、操作、常见问题几个方面展开。
📋 目录
  1. 适用场景与原理
  2. 编写一个自定义 API 接口
  3. 常见错误与调试
  4. 错误处理与数据校验
  5. 边界情况与性能考虑
A A

Nuxt 3 提供的 server routes 功能,可以让项目快速搭建后端 API 接口,而无需单独启动一个 Express 或 Nitro 服务。如果你正在开发一个全栈应用,或者需要一个简单的后端代理层,又不想引入额外的框架,server routes 是一个合适的选择。下面从场景、操作、常见问题几个方面展开。

在 Nuxt 3 中,server routes 的映射规则很简单:项目根目录下的 `server/api/` 文件夹中每个 `.ts` 或 `.js` 文件,都会自动暴露为一个 API 端点,文件路径即 API 路径。例如,`server/api/users.ts` 对应 `GET /api/users`。如果文件名包含多个层级,比如 `server/api/users/[id].ts`,则会生成动态路由,`[id]` 会被具体的参数值替换。注意文件名中不要包含空格或特殊符号,否则可能导致路由不匹配。

编写一个自定义 API 接口,首先在 `server/api/` 下创建文件,然后导出 `defineEventHandler` 函数。该函数接收一个 `event` 对象,通过 `event.context` 可以访问请求上下文。获取查询参数使用 `getQuery(event)`,获取动态路由参数使用 `getRouterParam(event, 'paramName')`,读取请求体使用 `await readBody(event)`。最后返回你想返回的数据,可以是对象、数组或字符串。示例如下:`export default defineEventHandler(async (event) => { const query = getQuery(event); return { message: 'Hel…

适用场景与原理

在 Nuxt 3 中,server routes 的映射规则很简单:项目根目录下的 server/api/ 文件夹中每个 .ts.js 文件,都会自动暴露为一个 API 端点,文件路径即 API 路径。例如,server/api/users.ts 对应 GET /api/users。如果文件名包含多个层级,比如 server/api/users/[id].ts,则会生成动态路由,[id] 会被具体的参数值替换。注意文件名中不要包含空格或特殊符号,否则可能导致路由不匹配。

这个机制基于 Nuxt 3 底层的 Nitro 引擎。当你部署时,这些路由会被编译为无服务器函数或传统 Node 服务。因此,你不需要额外配置路由表,文件系统即路由。这种做法适合中小型项目,或者微服务架构中的某个模块。如果你的 API 吞吐量极高,可能需要单独考虑性能调优。

Nuxt 3 如何使用 server routes 编写自定义 API 接口?

编写一个自定义 API 接口

编写一个自定义 API 接口,首先在 server/api/ 下创建文件,然后导出 defineEventHandler 函数。该函数接收一个 event 对象,通过 event.context 可以访问请求上下文。获取查询参数使用 getQuery(event),获取动态路由参数使用 getRouterParam(event, 'paramName'),读取请求体使用 await readBody(event)。最后返回你想返回的数据,可以是对象、数组或字符串。示例如下:export default defineEventHandler(async (event) => { const query = getQuery(event); return { message: 'Hello ' + query.name }; });

实际操作时,你需要根据 HTTP 方法决定是否读取请求体。默认情况下,defineEventHandler 会处理所有 HTTP 方法(GET、POST、PUT、DELETE 等)。如果你只想响应特定方法,可以在事件内部通过 event.node.req.method 判断。Nuxt 3 的 server routes 并没有内置路由方法过滤,这一点需要手动处理。

常见错误与调试

一个常见的错误是在异步处理器中忘记使用 await,例如读取 readBody 或调用外部 API 时。如果忘记 awaitreadBody 返回的是 Promise 对象,导致数据处理异常。另一个坑是动态路由参数名称必须与文件名中的占位符一致,比如文件名为 [id].ts,则只能使用 getRouterParam(event, 'id'),而不能写成 getRouterParam(event, 'ID')。此外,event.context 在服务端渲染期间可能包含 reqres,但不要在 API 中直接操作它们,以免干扰 Nuxt 的内部逻辑。

当你遇到 API 返回不符合预期时,可以先检查服务端终端日志。Nuxt 开发模式下,控制台会打印请求信息。如果返回 500 错误,查看输出中的堆栈跟踪。对于动态路由不匹配的情况,可以试着在浏览器访问 /api/__nuxt_vite_node__/...?(开发环境),但通常更简单的方法是直接使用 curl 测试:curl http://localhost:3000/api/users/123。如果返回 404,先确认文件名和路径大小写。Nuxt 3 在 Windows 和 macOS 文件系统不敏感,但在 Linux 服务器上是大小写敏感的。

错误处理与数据校验

API 中抛出错误应使用 createError 函数,它接受状态码和消息。例如 throw createError({ statusCode: 400, message: '参数缺失' })。这样可以确保错误以标准 JSON 格式返回给客户端。注意不要直接抛出字符串或普通 Error,否则可能导致 Nuxt 的错误处理流程异常。同时,避免在错误消息中泄露敏感信息(如数据库表结构、文件路径),建议只返回用户可见的错误提示。调试时,可以通过 console.error 在服务端控制台记录详细错误。

Nuxt 3 如何使用 server routes 编写自定义 API 接口?

对于 POST、PUT 等需要接收请求体的接口,务必对输入数据进行校验。可以先从 readBody 获取数据,然后使用简单的条件判断或第三方库(如 zod)验证字段类型和范围。例如:const body = await readBody(event); if (!body.name) { throw createError({ statusCode: 400, message: 'name 字段必填' }) }。注意,Nuxt 3 的 server routes 默认解析 JSON 请求体,但如果是 multipart/form-data 格式,需要额外处理(如使用 getQuery 解析参数)。建议统一使用 JSON 格式请求。

边界情况与性能考虑

当 API 需要操作数据库或外部服务时,要留意请求超时和并发问题。可以在 defineEventHandler 内部使用 Promise.race 设置超时,或使用 Nuxt 的 useStorage 缓存常用数据以减少重复请求。另外,server routes 默认是惰性加载的,首次请求可能触发编译,导致响应稍慢。生产环境中,可以预编译项目来避免。如果你在 API 中使用了 useRuntimeConfig,注意配置只在服务端可用,不要在客户端代码中引用。最后,测试 API 时,推荐使用 curl 或 Postman,并检查响应头中的 Content-Type 是否为 application/json

还有一个容易被忽略的点:server routes 中的 event 对象是 Nuxt 封装过的,你无法直接使用 Node.js 原生的 reqres 事件。例如,要设置自定义响应头,推荐使用 setHeader(event, 'X-Custom', 'value'),而不是直接操作 event.node.res。这样可以避免与 Nitro 内部逻辑冲突。

总之,Nuxt 3 的 server routes 为全栈开发提供了便利,但每个接口都需要考虑输入验证、错误处理和边界条件。按照上述步骤创建并测试接口后,你可以通过 nuxt build 构建生产版本,确认 API 在部署后也能正常工作。