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 }
})
Расширенное использование
Конфиг 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)
})