servidor
O diretório server/ é usado para registrar manipuladores de API e servidor em sua aplicação.
O Nuxt escaneia automaticamente os arquivos dentro desses diretórios para registrar manipuladores de API e servidor com suporte a Hot Module Replacement (HMR).
-| server/
---| api/
-----| hello.ts # /api/hello
---| routes/
-----| bonjour.ts # /bonjour
---| middleware/
-----| log.ts # log de todas as requisições
Cada arquivo deve exportar uma função padrão definida com defineEventHandler()
ou eventHandler()
(alias).
O manipulador pode retornar diretamente dados JSON, uma Promise
, ou usar event.node.res.end()
para enviar uma resposta.
export default defineEventHandler((event) => {
return {
hello: 'world'
}
})
Agora você pode chamar essa API universalmente em suas páginas e componentes:
<script setup lang="ts">
const { data } = await useFetch('/api/hello')
</script>
<template>
<pre>{{ data }}</pre>
</template>
Rotas do Servidor
Arquivos dentro de ~/server/api
são automaticamente prefixados com /api
em sua rota.
Para adicionar rotas de servidor sem o prefixo /api
, coloque-as no diretório ~/server/routes
.
Exemplo:
export default defineEventHandler(() => 'Hello World!')
Dado o exemplo acima, a rota /hello
estará acessível em http://localhost:3000/hello.
Observe que atualmente as rotas do servidor não suportam a funcionalidade completa de rotas dinâmicas como as páginas.
Middleware do Servidor
O Nuxt lerá automaticamente qualquer arquivo em ~/server/middleware
para criar middleware de servidor para seu projeto.
Os manipuladores de middleware serão executados em todas as requisições antes de qualquer outra rota do servidor para adicionar ou verificar cabeçalhos, registrar requisições ou estender o objeto de requisição do evento.
Os manipuladores de middleware não devem retornar nada (nem fechar ou responder à requisição) e apenas inspecionar ou estender o contexto da requisição ou lançar um erro.
Exemplos:
export default defineEventHandler((event) => {
console.log('Nova requisição: ' + getRequestURL(event))
})
export default defineEventHandler((event) => {
event.context.auth = { user: 123 }
})
Plugins do Servidor
O Nuxt lerá automaticamente qualquer arquivo no diretório ~/server/plugins
e os registrará como plugins Nitro. Isso permite estender o comportamento em tempo de execução do Nitro e conectar-se a eventos do ciclo de vida.
Exemplo:
export default defineNitroPlugin((nitroApp) => {
console.log('Plugin Nitro', nitroApp)
})
Utilitários do Servidor
As rotas do servidor são alimentadas por h3js/h3, que vem com um conjunto útil de auxiliares.
Veja também Auxiliares de Requisição H3 DisponíveisVocê pode adicionar mais auxiliares dentro do diretório ~/server/utils
.
Por exemplo, você pode definir um utilitário de manipulador personalizado que envolve o manipulador original e realiza operações adicionais antes de retornar a resposta final.
Exemplo:
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 {
// faça algo antes do manipulador de rota
const response = await handler(event)
// faça algo após o manipulador de rota
return { response }
} catch (err) {
// Tratamento de erro
return { err }
}
})
Tipos do Servidor
Este recurso está disponível a partir do Nuxt >= 3.5
Para melhorar a clareza dentro do seu IDE entre as importações automáticas de 'nitro' e 'vue', você pode adicionar um ~/server/tsconfig.json
com o seguinte conteúdo:
{
"extends": "../.nuxt/tsconfig.server.json"
}
Atualmente, esses valores não serão respeitados ao verificar tipos (nuxt typecheck
), mas você deve obter melhores dicas de tipo no seu IDE.
Receitas
Parâmetros de Rota
As rotas do servidor podem usar parâmetros dinâmicos dentro de colchetes no nome do arquivo, como /api/hello/[name].ts
, e serem acessadas via event.context.params
.
export default defineEventHandler((event) => {
const name = getRouterParam(event, 'name')
return `Hello, ${name}!`
})
Alternativamente, use getValidatedRouterParams
com um validador de esquema como Zod para segurança em tempo de execução e tipo.
Agora você pode chamar essa API universalmente em /api/hello/nuxt
e obter Hello, nuxt!
.
Correspondência de Método HTTP
Os nomes dos arquivos de manipulador podem ser sufixados com .get
, .post
, .put
, .delete
, ... para corresponder ao Método HTTP da requisição.
export default defineEventHandler(() => 'Manipulador de teste GET')
export default defineEventHandler(() => 'Manipulador de teste POST')
Dado o exemplo acima, ao buscar /test
com:
- Método GET: Retorna
Manipulador de teste GET
- Método POST: Retorna
Manipulador de teste POST
- Qualquer outro método: Retorna erro 405
Você também pode usar index.[method].ts
dentro de um diretório para estruturar seu código de forma diferente, isso é útil para criar namespaces de API.
export default defineEventHandler((event) => {
// manipular requisições GET para o endpoint `api/foo`
})
Rota Catch-all
Rotas catch-all são úteis para manipulação de rotas de fallback.
Por exemplo, criar um arquivo chamado ~/server/api/foo/[...].ts
registrará uma rota catch-all para todas as requisições que não correspondem a nenhum manipulador de rota, como /api/foo/bar/baz
.
export default defineEventHandler((event) => {
// event.context.path para obter o caminho da rota: '/api/foo/bar/baz'
// event.context.params._ para obter o segmento da rota: 'bar/baz'
return `Manipulador padrão foo`
})
Você pode definir um nome para a rota catch-all usando ~/server/api/foo/[...slug].ts
e acessá-lo via event.context.params.slug
.
export default defineEventHandler((event) => {
// event.context.params.slug para obter o segmento da rota: 'bar/baz'
return `Manipulador padrão foo`
})
Manipulação de Corpo
export default defineEventHandler(async (event) => {
const body = await readBody(event)
return { body }
})
Alternativamente, use readValidatedBody
com um validador de esquema como Zod para segurança em tempo de execução e tipo.
Agora você pode chamar essa API universalmente usando:
async function submit() {
const { body } = await $fetch('/api/submit', {
method: 'post',
body: { test: 123 }
})
}
Estamos usando submit.post.ts
no nome do arquivo apenas para corresponder a requisições com método POST
que podem aceitar o corpo da requisição. Ao usar readBody
dentro de uma requisição GET, readBody
lançará um erro HTTP 405 Method Not Allowed
.
Parâmetros de Consulta
Consulta de exemplo /api/query?foo=bar&baz=qux
export default defineEventHandler((event) => {
const query = getQuery(event)
return { a: query.foo, b: query.baz }
})
Alternativamente, use getValidatedQuery
com um validador de esquema como Zod para segurança em tempo de execução e tipo.
Tratamento de Erros
Se nenhum erro for lançado, um código de status 200 OK
será retornado.
Qualquer erro não capturado retornará um erro HTTP 500 Internal Server Error
.
Para retornar outros códigos de erro, lance uma exceção com createError
:
export default defineEventHandler((event) => {
const id = parseInt(event.context.params.id) as number
if (!Number.isInteger(id)) {
throw createError({
statusCode: 400,
statusMessage: 'ID deve ser um inteiro',
})
}
return 'Tudo certo'
})
Códigos de Status
Para retornar outros códigos de status, use o utilitário setResponseStatus
.
Por exemplo, para retornar 202 Accepted
export default defineEventHandler((event) => {
setResponseStatus(event, 202)
})
Configuração em Tempo de Execução
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
})
Passar o event
como argumento para useRuntimeConfig
é opcional, mas é recomendado passá-lo para obter a configuração em tempo de execução sobrescrita por variáveis de ambiente em tempo de execução para rotas do servidor.
Cookies de Requisição
export default defineEventHandler((event) => {
const cookies = parseCookies(event)
return { cookies }
})
Encaminhamento de Contexto e Cabeçalhos
Por padrão, nem os cabeçalhos da requisição recebida nem o contexto da requisição são encaminhados ao fazer requisições fetch em rotas do servidor. Você pode usar event.$fetch
para encaminhar o contexto da requisição e cabeçalhos ao fazer requisições fetch em rotas do servidor.
export default defineEventHandler((event) => {
return event.$fetch('/api/forwarded')
})
Cabeçalhos que não devem ser encaminhados não serão incluídos na requisição. Esses cabeçalhos incluem, por exemplo:
transfer-encoding
, connection
, keep-alive
, upgrade
, expect
, host
, accept
Aguardando Promises Após a Resposta
Ao lidar com requisições de servidor, você pode precisar realizar tarefas assíncronas que não devem bloquear a resposta ao cliente (por exemplo, cache e registro). Você pode usar event.waitUntil
para aguardar uma promise em segundo plano sem atrasar a resposta.
O método event.waitUntil
aceita uma promise que será aguardada antes que o manipulador termine, garantindo que a tarefa seja concluída mesmo que o servidor, de outra forma, encerrasse o manipulador logo após a resposta ser enviada. Isso se integra com provedores de tempo de execução para aproveitar suas capacidades nativas para lidar com operações assíncronas após a resposta ser enviada.
const timeConsumingBackgroundTask = async () => {
await new Promise((resolve) => setTimeout(resolve, 1000))
};
export default eventHandler((event) => {
// agendar uma tarefa em segundo plano sem bloquear a resposta
event.waitUntil(timeConsumingBackgroundTask())
// enviar imediatamente a resposta ao cliente
return 'feito'
});
Uso Avançado
Configuração do Nitro
Você pode usar a chave nitro
em nuxt.config
para definir diretamente a configuração do Nitro.
Esta é uma opção avançada. Configurações personalizadas podem afetar implantações de produção, pois a interface de configuração pode mudar ao longo do tempo quando o Nitro é atualizado em versões semver-minor do Nuxt.
export default defineNuxtConfig({
// https://nitro.build/config
nitro: {}
})
Roteador Aninhado
import { createRouter, defineEventHandler, useBase } from 'h3'
const router = createRouter()
router.get('/test', defineEventHandler(() => 'Hello World'))
export default useBase('/api/hello', router.handler)
Enviando Streams
Este é um recurso experimental e está disponível em todos os ambientes.
import fs from 'node:fs'
import { sendStream } from 'h3'
export default defineEventHandler((event) => {
return sendStream(event, fs.createReadStream('/path/to/file'))
})
Enviando Redirecionamento
export default defineEventHandler(async (event) => {
await sendRedirect(event, '/path/redirect/to', 302)
})
Manipulador ou Middleware Legado
export default fromNodeMiddleware((req, res) => {
res.end('Manipulador legado')
})
O suporte legado é possível usando h3js/h3, mas é aconselhável evitar manipuladores legados tanto quanto possível.
export default fromNodeMiddleware((req, res, next) => {
console.log('Middleware legado')
next()
})
Nunca combine o callback next()
com um middleware legado que seja async
ou retorne uma Promise
.
Armazenamento do Servidor
O Nitro fornece uma camada de armazenamento multiplataforma. Para configurar pontos de montagem de armazenamento adicionais, você pode usar nitro.storage
, ou plugins do servidor.
Exemplo de adição de um armazenamento Redis:
Usando nitro.storage
:
export default defineNuxtConfig({
nitro: {
storage: {
redis: {
driver: 'redis',
/* opções do conector redis */
port: 6379, // Porta do Redis
host: "127.0.0.1", // Host do Redis
username: "", // requer Redis >= 6
password: "",
db: 0, // Padrão é 0
tls: {} // tls/ssl
}
}
}
})
Então, no seu manipulador de API:
export default defineEventHandler(async (event) => {
// Listar todas as chaves com
const keys = await useStorage('redis').getKeys()
// Definir uma chave com
await useStorage('redis').setItem('foo', 'bar')
// Remover uma chave com
await useStorage('redis').removeItem('foo')
return {}
})
Alternativamente, você pode criar um ponto de montagem de armazenamento usando um plugin de servidor e configuração em tempo de execução:
import redisDriver from 'unstorage/drivers/redis'
export default defineNitroPlugin(() => {
const storage = useStorage()
// Passe dinamicamente as credenciais da configuração em tempo de execução, ou outras fontes
const driver = redisDriver({
base: 'redis',
host: useRuntimeConfig().redis.host,
port: useRuntimeConfig().redis.port,
/* outras opções do conector redis */
})
// Montar driver
storage.mount('redis', driver)
})
※Esta página é uma tradução não oficial da documentação oficial do Nuxt.js.
A página correspondente na documentação oficial está aqui:
https://nuxt.com/docs/3.x/guide/directory-structure/server