六维教程

Nuxt4 服务端接口

Nuxt 是全栈框架,server/ 目录可以直接写后端 API 接口,前后端在一个项目里,数据层到界面层的闭环不用再拆两个仓库。

server/ 目录与 Nitro

Nuxt 的服务端基于 Nitro 引擎。在 server/ 目录下创建文件即生成接口,文件名决定了请求方法:

server/api/
├── users.get.ts        →  GET  /api/users
├── users.post.ts       →  POST  /api/users
├── users/[id].get.ts   →  GET  /api/users/:id
└── users/[id].delete.ts →  DELETE  /api/users/:id

文件名后缀 .get.post 等就是 HTTP 方法,没有后缀则所有方法都匹配。

第一个接口

创建 server/api/hello.get.ts

export default defineEventHandler(() => {
  return { message: '你好,Nuxt' }
})

启动开发服务器,访问 http://localhost:3000/api/hello,会返回:

{ "message": "你好,Nuxt" }

defineEventHandler 是 Nuxt 提供的接口处理函数包装器,返回值会被自动序列化为 JSON。

常用请求处理

查询参数

// server/api/search.get.ts
export default defineEventHandler((event) => {
  const query = getQuery(event)
  return { keyword: query.keyword }
})

访问 /api/search?keyword=nuxt 返回 { "keyword": "nuxt" }

路径参数

// server/api/users/[id].get.ts
export default defineEventHandler((event) => {
  const id = getRouterParam(event, 'id')
  // 实际项目这里会查数据库
  return { id, name: `用户${id}` }
})

访问 /api/users/7 返回 { "id": "7", "name": "用户7" }

请求体

// server/api/users.post.ts
export default defineEventHandler(async (event) => {
  const body = await readBody(event)  // 读取 JSON 请求体
  return { received: body }
})

$fetch 测试:

const res = await $fetch('/api/users', {
  method: 'POST',
  body: { name: '张三' }
})

响应状态码

export default defineEventHandler((event) => {
  setResponseStatus(event, 201)  // 设置状态码
  return { ok: true }
})

错误返回

接口出错时返回 4xx 状态码,客户端才能正确处理:

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

  if (id === '999') {
    throw createError({
      statusCode: 404,
      statusMessage: '用户不存在'
    })
  }

  return { id, name: `用户${id}` }
})

客户端 useFetch 会把这个错误放进 error 中,见错误处理

完整增删改查示例

结合上面所学,一个简单的用户接口:

// server/api/users/index.get.ts
const users = [
  { id: 1, name: '张三' },
  { id: 2, name: '李四' }
]

export default defineEventHandler(() => {
  return users
})
// server/api/users/[id].delete.ts
export default defineEventHandler((event) => {
  const id = getRouterParam(event, 'id')
  return { success: true, deletedId: id }
})

提示:示例中数据存在内存里,重启服务就清空了。真实项目请配合数据库使用,可以参考本博客的Supabase 教程

客户端调用

服务端接口写好后,前端用 useFetch 直接调用站内路径即可,SSR 模式下接口在服务端请求,数据直接进页面 HTML:

<script setup>
const { data: users, refresh } = await useFetch('/api/users')

async function removeUser(id) {
  await $fetch(`/api/users/${id}`, { method: 'DELETE' })
  refresh()  // 刷新列表
}
</script>

<template>
  <ul>
    <li v-for="user in users" :key="user.id">
      {{ user.name }}
      <button @click="removeUser(user.id)">删除</button>
    </li>
  </ul>
</template>

前后端共享代码

shared/ 目录下的代码前后端都能引用,适合放公共常量、工具函数。比如把用户列表的初始数据抽出来共用:

// shared/data/users.js
export const demoUsers = [
  { id: 1, name: '张三' },
  { id: 2, name: '李四' },
]
// server/api/users.get.ts
import { demoUsers } from '~/shared/data/users'

export default defineEventHandler(() => {
  return demoUsers
})

接口速查表

需求 写法
查询参数 getQuery(event)
路径参数 getRouterParam(event, 'id')
请求体 readBody(event)
设置状态码 setResponseStatus(event, 201)
抛错 throw createError({ statusCode, statusMessage })
方法限定 文件名后缀 .get.ts.post.ts

一句话总结:在 server/api/ 建文件即接口,方法由文件名后缀决定,用 getQuerygetRouterParamreadBody 取数据,前端 useFetch 直接调站内路径完成闭环。

上一篇
Nuxt4 数据获取进阶
下一篇
Nuxt4 SEO 与页面元信息