Back

Como o Middleware Funciona no Node.js

Como o Middleware Funciona no Node.js

Você já viu app.use() espalhado por bases de código Express. Você sabe que o middleware fica entre requisições e respostas. Mas quando algo quebra nessa cadeia—uma requisição trava, um erro desaparece, ou handlers disparam na ordem errada—o modelo mental desmorona.

Este artigo explica como o middleware do Node.js realmente funciona: o que é, como o controle flui pela cadeia, e o que mudou no Express 5.

Principais Conclusões

  • Middleware é um padrão de framework, não uma funcionalidade do Node.js—o Express o implementa sobre o módulo http nativo
  • A ordem de execução importa: o middleware executa na ordem de registro, e os manipuladores de erro devem vir por último
  • A função next() controla o fluxo; omiti-la sem enviar uma resposta faz com que as requisições travem
  • O Express 5 captura nativamente promises rejeitadas de middleware assíncrono e route handlers, eliminando a necessidade de wrappers manuais

Middleware É um Padrão de Framework, Não uma Funcionalidade do Node.js

O Node.js em si não possui o conceito de middleware. O módulo http nativo fornece apenas um objeto de requisição e resposta—nada mais. Middleware é um padrão que frameworks como o Express implementam sobre o Node.js.

O middleware do Express segue uma estrutura específica: funções que recebem req, res e next. O framework mantém uma pilha dessas funções e as chama sequencialmente para cada requisição recebida. Esse ciclo de vida da requisição em frameworks Node.js é o que dá ao middleware seu poder.

Outros frameworks implementam padrões similares de forma diferente. O Koa usa um “modelo de cebola” onde o middleware envolve os handlers subsequentes. O Fastify usa hooks em pontos específicos do ciclo de vida. O conceito se transfere, mas a semântica não.

O Ciclo de Vida Requisição-Resposta

Quando uma requisição chega a uma aplicação Express, ela entra em um pipeline:

  1. O Express compara a requisição com middleware e rotas registrados
  2. Cada função middleware executa na ordem de registro
  3. O controle passa adiante via next() ou para quando uma resposta é enviada
  4. O middleware de tratamento de erros captura erros passados para next(err) e erros lançados ou rejeitados dentro de middleware e route handlers gerenciados pelo Express

A função next() é o mecanismo que move o controle pela cadeia. Chame-a, e o Express invoca o próximo middleware correspondente. Omita-a sem enviar uma resposta, e a requisição trava indefinidamente.

A Ordem do Middleware Importa

O middleware do Express executa na ordem em que você o registra. Isso não é apenas um detalhe—é a fundação dos padrões de middleware no Node.js.

app.use(parseBody)
app.use(authenticate)
app.use(authorize)
app.get('/data', handler)

Aqui, parseBody executa primeiro, tornando os dados da requisição disponíveis para authenticate. Troque a ordem deles, e a autenticação quebra porque o corpo ainda não foi analisado.

Essa ordenação também afeta o tratamento de erros. O middleware de tratamento de erros deve vir depois das rotas que ele protege.

Interrompendo a Resposta

O middleware pode encerrar o ciclo requisição-resposta antecipadamente enviando uma resposta sem chamar next(). É assim que o middleware de autenticação rejeita requisições não autorizadas:

function requireAuth(req, res, next) {
  if (!req.user) {
    return res.status(401).json({ error: 'Unauthorized' })
  }
  next()
}

Uma vez que res.send(), res.json() ou métodos similares executem, o middleware subsequente não será executado para aquela requisição. Essa interrupção é intencional e útil.

Middleware de Nível de Aplicação, Roteador e Rota

O middleware do Express se anexa em diferentes escopos:

Middleware de nível de aplicação executa para cada requisição à aplicação. Use app.use() para preocupações transversais como logging ou parsing de corpo.

Middleware de nível de roteador executa para requisições que correspondem a um roteador específico. Isso delimita o middleware a grupos de rotas sem afetar toda a aplicação.

Middleware de nível de rota executa apenas para rotas específicas. Passe funções middleware diretamente para definições de rota para comportamento direcionado como validação.

A distinção é sobre escopo, não capacidade. Todos os três usam a mesma assinatura de função.

Tratamento de Erros e Middleware no Express 5

O Express identifica middleware de tratamento de erros pela sua assinatura de quatro parâmetros: (err, req, res, next). Quando qualquer middleware chama next(err) ou lança um erro, o Express pula o middleware regular e vai direto para os manipuladores de erro.

O Express 5 muda como erros assíncronos funcionam. No Express 4, promises rejeitadas e exceções assíncronas exigiam tratamento manual ou wrappers de terceiros. O Express 5 captura nativamente promises rejeitadas de funções assíncronas e as roteia para manipuladores de erro automaticamente.

// Express 5: nenhum wrapper necessário
app.get('/data', async (req, res) => {
  const data = await fetchData() // rejeição dispara middleware de erro
  res.json(data)
})

app.use((err, req, res, next) => {
  res.status(500).json({ error: err.message })
})

O middleware de tratamento de erros ainda precisa ser registrado por último, depois das rotas e outros middleware.

Conclusão

Middleware é um padrão de nível de framework para processar requisições através de uma cadeia de funções. Entender a ordem de execução, o papel de next(), e onde colocar os manipuladores de erro elimina a maioria das dores de cabeça de depuração de middleware.

O tratamento de erros assíncronos nativo do Express 5 remove um ponto de dor comum, mas os fundamentos permanecem: registre o middleware na ordem correta, chame next() ou envie uma resposta, e coloque os manipuladores de erro no final.

Perguntas Frequentes

Se você esquecer de chamar next() e não enviar uma resposta, a requisição travará indefinidamente. O Express aguarda que next() seja chamado para continuar a cadeia, ou que uma resposta seja enviada ao cliente. Sempre garanta que seu middleware chame next() para passar o controle adiante ou envie uma resposta para encerrar o ciclo.

Sim, mas você deve tratar erros manualmente. O Express 4 não captura promises rejeitadas automaticamente, então rejeições não tratadas não dispararão seu middleware de tratamento de erros. Envolva código assíncrono em blocos try-catch ou use uma função wrapper que encaminhe erros para next(). O Express 5 elimina esse requisito capturando rejeições nativamente.

O middleware de tratamento de erros requer exatamente quatro parâmetros: err, req, res e next. Se você omitir qualquer parâmetro, o Express o trata como middleware regular e o pula durante o tratamento de erros. Também verifique se seu manipulador de erro está registrado depois de todas as rotas e outros middleware na sua aplicação.

Ambos registram middleware com a mesma assinatura de função, mas diferem em escopo. app.use() anexa middleware no nível da aplicação, executando para todas as requisições. router.use() anexa middleware a uma instância específica de roteador, executando apenas para requisições que correspondem ao caminho montado daquele roteador.

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay