Middleware
Middleware lhe permite interceptar requisições e respostas e injetar comportamentos dinamicamente toda vez que uma página ou endpoint for ser renderizado.
Isso também permite definir e compartilhar informações específicas da requisição entre endpoints e páginas alterando o objeto locals
que é disponibilizado em todos os componentes Astro e endpoints de API.
Middleware está disponível tanto para projetos Astro SSG quanto SSR.
Uso Básico
-
Crie um arquivo
src/middleware.js|ts
(Como alternativa, você pode criarsrc/middleware/index.js|ts
.) -
Dentro deste arquivo, exporte uma função
onRequest()
. Esta exportação não pode ser um default export.src/middleware.js export function onRequest ({ locals, request }, next) {// intercepta dados de uma requisição// opcionalmente, transforma a requisição modificando `locals`locals.titulo = "Novo Título";// retorna uma `Response` ou o resultado de chamar `next()`return next();}; -
Dentro de qualquer arquivo
.astro
, acesse os dados da resposta utilizandoAstro.locals
.
---const dados = Astro.locals;---<h1>{dados.titulo}</h1><p>Essa {dados.propriedade} veio do middleware.</p>
Tipos do Middleware
Você pode importar e utilizar a função utilitária defineMiddleware()
para se aproveitar da segurança de tipo:
import { defineMiddleware } from "astro:middleware";
// `context` e `next` são tipados automaticamenteexport const onRequest = defineMiddleware((context, next) => {
});
De outra forma, se você estiver utilizando JsDoc para se aproveitar da segurança de tipo, você pode utilizar MiddlewareRequestHandler
:
/** * @type {import("astro").MiddlewareResponseHandler} */// `context` e `next` são tipados automaticamenteexport const onRequest = (context, next) => {
};
Para tipar a informação dentro de Astro.locals
, o que lhe fornece preenchimento automático dentro de arquivos .astro
e do código do middleware,
declare um namespace global no arquivo env.d.ts
:
/// <reference types="astro/client" />declare namespace App { interface Locals { usuario: { nome: string }, tituloBoasVindas: () => string, compras: Map<string, object> }}
Então, dentro do arquivo do middleware, podemos nos aproveitar de preenchimento automático e segurança de tipos.
Você pode armazenar dados de qualquer tipo dentro de Astro.locals
: strings, numbers, e até mesmo tipos complexos como funções e maps.
export function onRequest ({ locals, request }, next) { // intercepta dados de resposta de uma requisição // opcionalmente, transforma a resposta modificando `locals` locals.usuario.nome = "John Wick"; locals.tituloBoasVindas = () => { return "Bem-vindo de volta, " + locals.usuario.nome; };
// retorna uma `Response` ou o resultado de chamar `next()` return next();};
Desta forma você pode utilizar essas informações dentro de qualquer arquivo .astro
.
---const titulo = Astro.locals.tituloBoasVindas();const compras = Array.from(Astro.locals.compras.entries());---<h1>{titulo}</h1><p>Essa {data.propriedade} veio do middleware.</p><ul> {compras.map(compra => { return <li>{/* faça algo com cada compra */}</li>; })}</ul>
Exemplo: editando informações sensíveis
O exemplo abaixo utiliza middleware para substituir “INFORMAÇÃO PESSOAL” pela palavra “REMOVIDO” para lhe permitir renderizar HTML modificado na sua página:
export const onRequest = async (context, next) => { const resposta = await next(); const html = await response.text(); const htmlDaResposta = html.replaceAll("INFORMAÇÃO PESSOAL", "REMOVIDO");
return new Response(redactedHtml, { status: 200, headers: response.headers });};
Encadeando middleware
Múltiplos middlewares podem ser conectados em uma sequência ordenada utilizando sequence()
:
import { sequence } from "astro:middleware";
async function validacao(_, next) { console.log("validação da requisição"); const resposta = await next(); console.log("validação da resposta"); return resposta;}
async function auth(_, next) { console.log("autenticação da requisição"); const resposta = await next(); console.log("autenticação da resposta"); return resposta;}
async function cumprimentos(_, next) { console.log("cumprimentos da requisição"); const resposta = await next(); console.log("comprimentos da resposta"); return resposta;}
export const onRequest = sequence(validacao, auth, cumprimentos);
O exemplo acima resultará na seguinte ordem no terminal:
validação da requisiçãoautenticação da requisiçãocumprimentos da requisiçãocumprimentos da respostaautenticação da respostavalidação da resposta
Referência da API
onRequest()
Uma função exportada obrigatória do arquivo src/middleware.js
que será chamada antes da renderização de cada página ou rota da API.
Ela aceita dois argumentos opcionais: context e next().
onRequest()
deve retornar uma Response
: ou diretamente, ou chamando next()
.
context
Um objeto que inclui informações a serem disponibilizadas para outro middleware, rotas de API e rotas .astro
durante o processo de renderização.
Esse é um argumento opcional passado para onRequest()
que pode conter o objeto locals
junto com qualquer propriedade adicional a ser compartilhada durante a renderização.
Por exemplo, o objeto context
pode incluir cookies utilizados para autenticação.
Esse é o mesmo objeto context
que é passada para as rotas de API.
next()
Uma função que intercepta (lê e modifica) a resposta (Response
) de uma requisição (Request
) ou invoca o próximo middleware na sequência e retorna uma Response
.
Por exemplo, essa função pode modificar o corpo HTML de uma resposta.
Esse é um argumento opcional de onRequest()
, e pode prover a Response
que o middleware deve retornar.
locals
Um objeto contendo dados de uma Response
que podem ser manipulados dentro do middleware.
Esse objeto locals
é repassado através do processo de manipulação da requisição e é diponibilizado como uma propriedade em APIContext
e AstroGlobal
.
Isso permite que dados sejam compartilados entre middlewares, rotas da API, e páginas .astro
. Isso é útil para armazenar dados específicos de uma chamada, como dados do usuário, através das etapas de renderização.
locals
é um objeto que vive e morre dentro de uma única rota Astro; quando a página da sua rota for renderizada, locals
deixará de existir e um novo objeto será criado.
Informações que precisarem ser persistidas através de múltiplas páginas devem ser armazenadas em outro lugar.
O valor de locals
não pode ser sobrescrito tem tempo de execução. Fazer isso causaria um risco descartar toda a informação armazenada pelo usuário. Em modo de desenvolvimento (dev
), Astro executa validações e emitirá um erro se locals
for sobrescrito.
sequence()
Uma função que aceita funções de middleware como argumentos, e os executará na ordem que foram passados.
createContext
Uma API de baixo nível para criar um APIContext
que pode ser utilizado pelo middleware Astro.
Essa função pode ser usada por integrações/adaptadores para executar programaticamente os middlewares Astro.
trySerializeLocals
Uma API de baixo nível que recebe qualquer valor e tenta retornar uma versão serializada (uma string) desse valor. Se o valor não puder ser serializado, essa função irá lançar um erro de runtime.
Learn