Pular para o conteúdo

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.

  1. Crie um arquivo src/middleware.js|ts (Como alternativa, você pode criar src/middleware/index.js|ts.)

  2. Dentro deste arquivo, exporte uma função onRequest() (EN) que pode receber um object context e uma função next(). Esse não pode ser a exportação padrão (export default).

    src/middleware.js
    export function onRequest ({ locals, request }, next) {
    // intercepta dados de uma requisição
    // opcionalmente, modifica as propriedades em `locals`
    locals.titulo = "Novo Título";
    // retorna uma `Response` ou o resultado de chamar `next()`
    return next();
    };
  3. Dentro de qualquer arquivo .astro, acesse os dados da resposta utilizando Astro.locals.

    src/components/Componente.astro
    ---
    const dados = Astro.locals;
    ---
    <h1>{dados.titulo}</h1>
    <p>Essa {dados.propriedade} veio do middleware.</p>

O object context inclui informações que serão disponibilizadas para outros middlewares, rotas de API e rotas .astro durante o processo de renderização.

Esse é um argumento opcional passado para onRequest() que pode contar o objecto locals assim como propriedades adicionais a serem compartilhadas durante a renderização. Por exemplo, o objecto context pode incluir cookies utilizados para autenticação.

Armazenando informações em context.locals

Seção intitulada Armazenando informações em context.locals

context.locals é um objeto que pode ser manipulado dentro do middleware.

Esse objeto locals é encaminhado através do processamento da chamada e é disponibilizado como um propriedade em APIContext e AstroGlobal. Isso permite que dados sejam compartilhados entre middlewares, rotas de API, e páginas .astro. Isso é útil para armazenar dados específicos de uma chamada, como dados do usuário, entre processos de renderização.

Você pode armazenar dados de qualquer tipo dentro de locals: strings, numbers, e até mesmo tipos complexos como funções e maps.

src/middleware.js
export function onRequest ({ locals, request }, next) {
// intercepta dados de uma requisição
// opcionalmente, modifica as propriedades em `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 com Astro.locals.

src/pages/compras.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>

locals é um objeto que vive e morre dentro de uma única rota AStro; quando a página de sua rota for renderizada, locals não existirá mais e um novo será criado. Informação que precise persistir entre chamadas para múltiplas páginas devem ser armazenas em outro lugar.

Exemplo: editando informações sensíveis

Seção intitulada 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:

src/middleware.js
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
});
};

Você pode importar e utilizar a função utilitária defineMiddleware() para se aproveitar da segurança de tipo:

src/middleware.ts
import { defineMiddleware } from "astro:middleware";
// `context` e `next` são tipados automaticamente
export 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:

src/middleware.js
/**
* @type {import("astro").MiddlewareResponseHandler}
*/
// `context` e `next` são tipados automaticamente
export 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:

src/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.

Múltiplos middlewares podem ser conectados em uma sequência ordenada utilizando sequence() (EN):

src/middleware.js
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:

Janela do terminal
validação da requisição
autenticação da requisição
cumprimentos da requisição
cumprimentos da resposta
autenticação da resposta
validação da resposta
Contribute

What’s on your mind?

Create GitHub Issue

Quickest way to alert our team of a problem.

Community