跳至主要內容

6. 服务端程序

鸭梨大约 3 分钟

6. 服务端程序

server/ 目录用于在应用中注册 API 和服务器处理程序。

每个文件应该默认导出由 defineEventHandler()eventHandler() 定义的函数。

处理程序可以直接返回 JSON 数据、Promise,或使用 event.node.res.end() 发送响应。

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

6.1 服务器路由

路由参数

服务器路由可以使用文件名中括号内的动态参数,例如 /api/hello/[name].ts,并通过 event.context.params 访问。

// server/api/hello/[name].ts
export default defineEventHandler((event) => {
  const name = getRouterParam(event, 'name')
  return `Hello, ${name}!`
})

也可以配合验证器使用:

// server/api/hello/[name].ts
import { z } from 'zod'

const userSchema = z.object({
  name: z.string().default('Guest'),
  email: z.string().email(),
})

export default defineEventHandler(async (event) => {
  const result = await readValidatedBody(event, body => userSchema.safeParse(body))
  // or `.parse` to directly throw an error

  if (!result.success)
    throw result.error.issues

  // User object is validated and typed!
  return result.data
})

匹配 HTTP 方法

可以使用形如 name.[method].ts 的文件名来匹配 HTTP 方法,例如 hello.get.ts

// server/api/hello.get.ts
export default defineEventHandler((event) => {
  return '...'
})

全局捕获路由

使用形如 [...].ts[...slug].ts 文件名来捕获所有路由,其中可以通过 event.context.params.slug 获得 slug 的值。

读取请求体

使用 readBody(event) 或者使用 readValidatedBody(event) 来读取请求体。

$fetch() 一起使用,可以自动包装/解包 JSON 数据。

注意

如果在 GET 等不支持请求体的方法中使用 readBody(event),将会抛出错误并返回 405。

读取查询参数

使用 getQuery(event) 或者使用 getValidatedQuery(event) 来读取查询参数。

读取 Cookies

使用 parseCookies(event) 来读取请求中的 Cookies。

错误处理

在每个请求处理程序中,可以使用 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'
})

可以使用 setResponseStatus(event, code) 来设置响应状态码。

配置

可使用 useRuntimeConfig() 来读取运行时配置。

将事件作为参数提供给 useRuntimeConfig() 是可选的,但建议传递它以获取服务器路由在运行时被环境变量覆盖的运行时配置。

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
})

现在,环境变量 NUXT_GITHUB_TOKEN 将覆盖自定义的 config.githubToken 值。

重定向

export default defineEventHandler(async (event) => {
  await sendRedirect(event, '/path/redirect/to', 302)
})

6.2 中间件

6.3 插件

6.4 高级

发送流

实验性 现在可以使用 sendStream(event, stream) 来发送流。

import fs from 'node:fs'
import { sendStream } from 'h3'

export default defineEventHandler((event) => {
  return sendStream(event, fs.createReadStream('/path/to/file'))
})

服务端 K/V 存储

Nitro 集成了 unjs/unstorageopen in new window,支持在服务端存储 K/V 信息。可安装各种适配器以支持不同环境和中间件。请阅读 官方文档open in new window 了解详细信息。

下面以 Redis 为例:

// nuxt.config.ts
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
      }
    }
  }
})

使用:

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 {}
})

WebSocket

建议使用 Socket.IOopen in new window 等成熟的库来处理 WebSocket,Nuxt3 可用的库如 nuxt-socket-io
open in new window