server
Nuxt автоматически сканирует файлы внутри этих директорий для регистрации API и серверных обработчиков с поддержкой горячей замены модулей (HMR).
-| server/
---| api/
-----| hello.ts      # /api/hello
---| routes/
-----| bonjour.ts    # /bonjour
---| middleware/
-----| log.ts        # логирование всех запросов
Каждый файл должен экспортировать функцию по умолчанию, определенную с помощью defineEventHandler() или eventHandler() (псевдоним).
Обработчик может напрямую возвращать данные JSON, Promise или использовать event.node.res.end() для отправки ответа.
export default defineEventHandler((event) => {
  return {
    hello: 'мир'
  }
})
Теперь вы можете повсеместно вызывать этот API на страницах и в компонентах:
<script setup lang="ts">
const { data } = await useFetch('/api/hello')
</script>
<template>
  <pre>{{ data }}</pre>
</template>
Роуты сервера
Файлы внутри ~/server/api автоматически получают префикс /api в своем роуте.
Чтобы добавить серверные роуты без префикса /api, поместите их в директорию ~/server/routes.
Пример:
export default defineEventHandler(() => 'Привет мир!')
Учитывая приведенный выше пример, маршрут /hello будет доступен по адресу http://localhost:3000/hello.
Серверные middleware
Nuxt автоматически прочитает любой файл в ~/server/middleware, чтобы создать серверную middleware для проекта.
Обработчики middleware будут запускаться для каждого запроса до того, как любой другой серверный маршрут будет добавлен или проверен - для добавления заголовков, регистрации запросов или расширения объекта запроса события.
Примеры:
export default defineEventHandler((event) => {
  console.log('Новый запрос: ' + getRequestURL(event))
})
export default defineEventHandler((event) => {
  event.context.auth = { user: 123 }
})
Серверные плагины
Nuxt автоматически прочитает все файлы в директории ~/server/plugins и зарегистрирует их как плагины Nitro. Это позволяет расширить рантайм-поведение Nitro и подключиться к событиям жизненного цикла.
Пример:
export default defineNitroPlugin((nitroApp) => {
  console.log('Плагин Nitro', nitroApp)
})
Серверные утилиты
Роуты сервера работают на основе unjs/h3, который поставляется с удобным набором хелперов.
Вы можете самостоятельно добавить больше хелперов в директорию ~/server/utils.
Например, вы можете определить пользовательскую утилиту-обработчик, которая оборачивает исходный обработчик и выполняет дополнительные операции перед возвратом окончательного ответа.
Пример:
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 {
      // сделать что-то до обработчика маршрута
      const response = await handler(event)
      // сделать что-то после обработчика маршрута
      return { response }
    } catch (err) {
      // Обработка ошибки
      return { err }
    }
  })
Серверные типы
Чтобы улучшить ясность в вашей IDE между автоматическим импортом из 'nitro' and 'vue', вы можете добавить ~/server/tsconfig.json со следующим содержимым:
{
  "extends": "../.nuxt/tsconfig.server.json"
}
В настоящее время эти значения не будут учитываться при проверке типов (nuxi typecheck), но вы должны получить более точные подсказки по типам в своей IDE.
Рецепты
Параметры роута
Роуты сервера могут использовать динамические параметры в квадратных скобках в имени файла, например /api/hello/[name].ts, и к ним можно получить доступ через event.context.params.
export default defineEventHandler((event) => {
  const name = getRouterParam(event, 'name')
  return `Привет, ${name}!`
})
getValidatedRouterParams с валидатором схемы, таким как Zod, для обеспечения безопасности рантайма и безопасности типов.Теперь вы можете повсеместно вызвать этот API по адресу /api/hello/nuxt и получить Привет, nuxt!.
Соответствие метода HTTP
Имена файлов дескрипторов могут иметь суффиксы .get, .post, .put, .delete, ... для соответствия методу HTTP запроса.
export default defineEventHandler(() => 'Тестовый обработчик get')
export default defineEventHandler(() => 'Тестовый обработчик post')
Учитывая пример выше, выборка /test с помощью:
- Метода GET: Возвращает Тестовый обработчик get
- Метода POST: Возвращает Тестовый обработчик post
- Любого другого метода: Возвращает ошибку 405
Вы также можете использовать index.[method].ts внутри директории для структурирования кода по-другому. Это полезно для создания пространств имен API.
export default defineEventHandler((event) => {
  // обрабатывает GET-запросы для эндпоинта `api/foo`
})
Универсальные роуты
Универсальные роуты полезны для обработки всех остальных маршрутов.
Например, создание файла с именем ~/server/api/foo/[...].ts зарегистрирует универсальный роут для всех запросов, которые не соответствуют ни одному обработчику, например /api/foo/bar/baz.
export default defineEventHandler((event) => {
  // event.context.path чтобы получить путь роута: '/api/foo/bar/baz'
  // event.context.params._ чтобы получить сегмент роута: 'bar/baz'
  return `Обработчик foo по умолчанию`
})
Вы можете задать имя для универсального роута с помощью ~/server/api/foo/[...slug].ts и получить к нему доступ через event.context.params.slug.
export default defineEventHandler((event) => {
  // event.context.params.slug чтобы получить сегмент роута: 'bar/baz'
  return `Обработчик foo по умолчанию`
})
Обработка тела запроса
export default defineEventHandler(async (event) => {
  const body = await readBody(event)
  return { body }
})
readValidatedBody с валидатором схемы, таким как Zod, для обеспечения безопасности рантайма и безопасности типов.Теперь вы можете повсеместно вызывать этот API, используя:
<script setup lang="ts">
async function submit() {
  const { body } = await $fetch('/api/submit', {
    method: 'post',
    body: { test: 123 }
  })
}
</script>
submit.post.ts в имени файла только для сопоставления запросов с методом POST, который может принять тело запроса. При использовании readBody в запросе GET, readBody выдаст ошибку HTTP 405 Method Not Allowed.Параметры запроса
Пример запроса /api/query?foo=bar&baz=qux
export default defineEventHandler((event) => {
  const query = getQuery(event)
  return { a: query.foo, b: query.baz }
})
getValidatedQuery с валидатором схемы, таким как Zod, для обеспечения безопасности рантайма и безопасности типов.Обработка ошибок
Если ошибок не возникло, будет возвращен код состояния 200 OK.
Любые неперехваченные ошибки вернут HTTP-ошибку 500 Internal Server Error.
Чтобы вернуть другие коды ошибок, вызовите исключение с помощью createError:
export default defineEventHandler((event) => {
  const id = parseInt(event.context.params.id) as number
  if (!Number.isInteger(id)) {
    throw createError({
      statusCode: 400,
      statusMessage: 'ID должен быть целым числом',
    })
  }
  return 'Все хорошо'
})
Коды статуса
Чтобы вернуть другие коды статуса, используйте утилиту setResponseStatus.
Например, чтобы вернуть 202 Accepted
export default defineEventHandler((event) => {
  setResponseStatus(event, 202)
})
Конфигурация рантайма
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
})
event в качестве аргумента useRuntimeConfig необязательно, но рекомендуется передать его, чтобы перезаписать конфигурацию рантайма переменными окружения во время выполнения для серверных роутов.Запрос Cookies
export default defineEventHandler((event) => {
  const cookies = parseCookies(event)
  return { cookies }
})
Передача контекста и заголовков
По умолчанию ни заголовки входящего запроса, ни контекст запроса не передаются при выполнении fetch-запросов в серверных маршрутах. Вы можете использовать event.$fetch, чтобы передать контекст запроса и заголовки при выполнении fetch-запросов в серверных маршрутах.
export default defineEventHandler((event) => {
  return event.$fetch('/api/forwarded')
})
transfer-encoding, connection, keep-alive, upgrade, expect, host, acceptРасширенное использование
Конфиг Nitro
Вы можете использовать ключ nitro в nuxt.config, чтобы напрямую задать конфигурацию Nitro.
export default defineNuxtConfig({
  // https://nitro.unjs.io/config
  nitro: {}
})
Вложенный роутер
import { createRouter, defineEventHandler, useBase } from 'h3'
const router = createRouter()
router.get('/test', defineEventHandler(() => 'Привет мир'))
export default useBase('/api/hello', router.handler)
Отправка стримов
import fs from 'node:fs'
import { sendStream } from 'h3'
export default defineEventHandler((event) => {
  return sendStream(event, fs.createReadStream('/path/to/file'))
})
Отправка редиректа
export default defineEventHandler(async (event) => {
  await sendRedirect(event, '/path/redirect/to', 302)
})
Устаревший обработчик или middleware
export default fromNodeMiddleware((req, res) => {
  res.end('Устаревший обработчик')
})
export default fromNodeMiddleware((req, res, next) => {
  console.log('Устаревшая middleware')
  next()
})
next() с устаревшей middleware, которая является async или возвращает Promise.Серверное хранилище
Nitro предоставляет кроссплатформенный слой хранения. Для настройки дополнительных точек монтирования хранилища можно использовать nitro.storage или серверные плагины.
Пример добавления хранилища Redis:
Использование nitro.storage:
export default defineNuxtConfig({
  nitro: {
    storage: {
      redis: {
        driver: 'redis',
        /* параметры коннектора redis */
        port: 6379, // порт Redis
        host: "127.0.0.1", // хост Redis
        username: "", // для Redis >= 6
        password: "",
        db: 0, // по умолчанию 0
        tls: {} // tls/ssl
      }
    }
  }
})
Затем в вашем обработчике API:
export default defineEventHandler(async (event) => {
  // Список всех ключей
  const keys = await useStorage('redis').getKeys()
  // Установка ключа
  await useStorage('redis').setItem('foo', 'bar')
  // Удаление ключа
  await useStorage('redis').removeItem('foo')
  return {}
})
В качестве альтернативы вы можете создать точку монтирования хранилища с помощью серверного плагина и конфигурации рантайма:
import redisDriver from 'unstorage/drivers/redis'
export default defineNitroPlugin(() => {
  const storage = useStorage()
  // Динамическая передача учетных данных из рантайм-конфигурации или других источников.
  const driver = redisDriver({
      base: 'redis',
      host: useRuntimeConfig().redis.host,
      port: useRuntimeConfig().redis.port,
      /* другие опции коннектора redis */
    })
  // Монтирование драйвера
  storage.mount('redis', driver)
})