O que middleware e app.use realmente significam no Expressjs?

228

Quase todos os aplicativos Express que vejo têm uma app.usedeclaração para middleware, mas não encontrei uma explicação clara e concisa sobre o que realmente é o middleware e o que a app.usedeclaração está fazendo. Até os próprios documentos expressos são um pouco vagos sobre isso. Você pode me explicar esses conceitos, por favor?

iZ.
fonte
3
pergunta semelhante para referência (embora esta tenha sido criada anteriormente): stackoverflow.com/questions/11321635/…
ericsoco
43
^ Ha! Essas duas perguntas se referem nos comentários.
Julian H. Lam
17
Portanto, é uma referência circular.
Steve K
6
Middleware Express.js desmistificado Um ótimo post sobre o tópico. Isso foi copiado e colado aqui antes, o que é plágio, é claro, mas o post original ainda é realmente útil, então deixo um link aqui.
totymedli
1
Eu escrevi um artigo sobre o express.js middleware. Aqui está o link: nodexplained.com/blog-detail/2017/12/31/…
shrawan_lakhe

Respostas:

111

middleware

Estou na metade da separação do conceito de middleware em um novo projeto.

O middleware permite definir uma pilha de ações pelas quais você deve fluir. Os servidores Express são uma pilha de middlewares.

// express
var app = express();
// middleware
var stack = middleware();

Em seguida, você pode adicionar camadas à pilha de middleware chamando .use

// express
app.use(express.static(..));
// middleware
stack.use(function(data, next) {
  next();
});

Uma camada na pilha de middleware é uma função, que recebe n parâmetros (2 para express, req& res) e uma nextfunção.

O middleware espera que a camada faça alguns cálculos, aumente os parâmetros e depois chame next.

Uma pilha não faz nada, a menos que você lide com ela. O Express manipula a pilha toda vez que uma solicitação HTTP recebida é capturada no servidor. Com o middleware, você lida com a pilha manualmente.

// express, you need to do nothing
// middleware
stack.handle(someData);

Um exemplo mais completo:

var middleware = require("../src/middleware.js");

var stack = middleware(function(data, next) {
    data.foo = data.data*2;
    next();
}, function(data, next) {
    setTimeout(function() {
        data.async = true;
        next();
    }, 100)
}, function(data) {
    console.log(data);
});

stack.handle({
    "data": 42
})

Em termos expressos, você apenas define uma pilha de operações que deseja expressar para cada solicitação HTTP recebida.

Em termos de expresso (em vez de conexão), você possui um middleware global e encaminha um middleware específico. Isso significa que você pode anexar uma pilha de middleware a todas as solicitações HTTP recebidas ou apenas anexá-las a solicitações HTTP que interagem com uma determinada rota.

Exemplos avançados de express & middleware:

// middleware 

var stack = middleware(function(req, res, next) {
    users.getAll(function(err, users) {
        if (err) next(err);
        req.users = users;
        next();  
    });
}, function(req, res, next) {
    posts.getAll(function(err, posts) {
        if (err) next(err);
        req.posts = posts;
        next();
    })
}, function(req, res, next) {
    req.posts.forEach(function(post) {
        post.user = req.users[post.userId];
    });

    res.render("blog/posts", {
        "posts": req.posts
    });
});

var app = express.createServer();

app.get("/posts", function(req, res) {
   stack.handle(req, res); 
});

// express

var app = express.createServer();

app.get("/posts", [
    function(req, res, next) {
        users.getAll(function(err, users) {
            if (err) next(err);
            req.users = users;
            next();  
        });
    }, function(req, res, next) {
        posts.getAll(function(err, posts) {
            if (err) next(err);
            req.posts = posts;
            next();
        })
    }, function(req, res, next) {
        req.posts.forEach(function(post) {
            post.user = req.users[post.userId];
        });

        res.render("blog/posts", {
            "posts": req.posts
        });
    }
], function(req, res) {
   stack.handle(req, res); 
});
Raynos
fonte
4
Hmm ... nesse caso, o middleware é sua própria biblioteca ou parte do express?
iZ.
5
Legal. Ainda estou um pouco confuso com a app.use()sintaxe. Qual é o valor de retorno real do middleware e o que usefaz com ele?
iZ.
9
O uso do @iZ o adiciona a uma pilha. Então, cada solicitação passa pela pilha.
Raynos 9/09/11
7
@ Raynos, o link para o seu projeto, "middleware", está quebrado.
Lee
1
@ Raynos, mas vejo o middleware ainda sendo usado no Express? Como assim, está nuked?
Timo Huovinen
60

Após simplificar as coisas, um servidor da web pode ser visto como uma função que recebe uma solicitação e gera uma resposta. Portanto, se você visualizar um servidor da Web como uma função, poderá organizá-lo em várias partes e separá-los em funções menores, para que a composição deles seja a função original.

Middlewares são as funções menores que você pode compor com outras pessoas e o benefício óbvio é que você pode reutilizá-las.

Barum Rho
fonte
33

Eu adiciono uma resposta tardia para adicionar algo não mencionado nas respostas anteriores.

Agora, deve ficar claro que o middleware é / são funções executadas entre a solicitação do cliente e a resposta do servidor . As funcionalidades mais comuns do middleware necessárias são gerenciamento de erros, interação com o banco de dados, obtenção de informações de arquivos estáticos ou outros recursos. Para avançar na pilha de middleware, o próximo retorno de chamada deve ser chamado, você pode vê-lo no final da função de middleware para avançar para a próxima etapa do fluxo.

Você pode usar a app.useabordagem e ter um fluxo como este :

var express = require('express'),
    app = express.createServer(),                                                                                                                                                 
    port = 1337;

function middleHandler(req, res, next) {
    console.log("execute middle ware");
    next();
}

app.use(function (req, res, next) {
    console.log("first middle ware");                                                                                                             
    next();
});

app.use(function (req, res, next) {
    console.log("second middle ware");                                                                                                             
    next();
});

app.get('/', middleHandler, function (req, res) {
    console.log("end middleware function");
    res.send("page render finished");
});

app.listen(port);
console.log('start server');

mas você também pode usar outra abordagem e passar cada middleware como argumentos de função. Aqui está um exemplo do site do MooTools Nodejs, em que o midleware obtém o fluxo do Twitter, Github e Blog antes de responseser enviado de volta ao cliente. Observe como as funções são passadas como argumentos em app.get('/', githubEvents, twitter, getLatestBlog, function(req, res){. O uso app.getserá chamado apenas para solicitações GET, app.useserá chamado para todas as solicitações.

// github, twitter & blog feeds
var githubEvents = require('./middleware/githubEvents')({
    org: 'mootools'
});
var twitter = require('./middleware/twitter')();
var blogData = require('./blog/data');
function getLatestBlog(req, res, next){
    blogData.get(function(err, blog) {
        if (err) next(err);
        res.locals.lastBlogPost = blog.posts[0];
        next();
    });
}

// home
app.get('/', githubEvents, twitter, getLatestBlog, function(req, res){
    res.render('index', {
        title: 'MooTools',
        site: 'mootools',
        lastBlogPost: res.locals.lastBlogPost,
        tweetFeed: res.locals.twitter
    });
});
Sergio
fonte
2
Eu estava procurando uma resposta para saber se o Express.js suporta a montagem de middleware baseada em rota (NÃO baseada em roteador)? Parece que você mostrou isso em sua resposta.
Selçuk
Você pode explicar o exemplo acima ?, como você pode passar tantas funções para o app.get (...) e para que ordem elas são chamadas?
Tanner Summers
2
Olá @TannerSummers, o .get()método utiliza 3 tipos de argumentos: o primeiro, o último e o do meio. Internamente, ele detecta se há mais argumentos que 2 e os usa (os do meio) como funções de middleware, chamando-os da esquerda para a direita.
288 Sergio Sergio
22

O guia expressjs tem uma resposta bastante clara à sua pergunta, eu recomendo que você leia isso, estou postando um pequeno trecho do guia, o guia é muito bom.

Escrevendo middleware para uso em aplicativos Express

Visão geral

Funções de middleware são funções que têm acesso ao objeto de solicitação ( req ), ao objeto de resposta ( res ) e à próxima função no ciclo de solicitação-resposta do aplicativo. A próxima função é uma função no roteador Express que, quando chamada, executa o middleware que sucede ao middleware atual.

As funções de middleware podem executar as seguintes tarefas:

  • Execute qualquer código.
  • Faça alterações na solicitação e nos objetos de resposta.
  • Finalize o ciclo de solicitação-resposta.
  • Ligue para o próximo middleware na pilha.

Se a função atual do middleware não encerrar o ciclo de solicitação-resposta, ela deverá chamar next () para passar o controle para a próxima função do middleware. Caso contrário, a solicitação será interrompida.

insira a descrição da imagem aqui

Exemplo

Aqui está um exemplo de um aplicativo Express "Hello World" simples. O restante deste artigo definirá e adicionará duas funções de middleware ao aplicativo: uma chamada myLogger que imprime uma mensagem de log simples e outra chamada requestTime 1 que exibe o registro de data e hora da solicitação HTTP.

var express = require('express')
var app = express()

app.get('/', function (req, res) {
  res.send('Hello World!')
})

app.listen(3000)   

Função de middleware myLogger

Aqui está um exemplo simples de uma função de middleware chamada "myLogger". Esta função apenas imprime "LOGGED" quando uma solicitação para o aplicativo passa por ela. A função de middleware é atribuída a uma variável chamada myLogger.

var myLogger = function (req, res, next) {
  console.log('LOGGED')
  next()
}

Observe a chamada acima para a próxima () . A chamada dessa função chama a próxima função de middleware no aplicativo. A função next () não faz parte da API Node.js ou Express, mas é o terceiro argumento que é passado para a função middleware. A função next () pode ter o nome de qualquer coisa, mas por convenção ela sempre é chamada de "next". Para evitar confusão, sempre use esta convenção.

Para carregar a função de middleware, chame app.use () , especificando a função de middleware. Por exemplo, o código a seguir carrega a função de middleware myLogger antes da rota para o caminho raiz (/).

var express = require('express')
var app = express()

var myLogger = function (req, res, next) {
  console.log('LOGGED')
  next()
}

app.use(myLogger)

app.get('/', function (req, res) {
  res.send('Hello World!')
})

app.listen(3000)

Toda vez que o aplicativo recebe uma solicitação, ele imprime a mensagem "LOGGED" no terminal.

A ordem de carregamento do middleware é importante: as funções do middleware carregadas primeiro também são executadas primeiro.

Se o myLogger for carregado após a rota para o caminho raiz, a solicitação nunca o alcançará e o aplicativo não imprimirá “LOGGED”, porque o manipulador de rota do caminho raiz encerra o ciclo de solicitação-resposta.

A função de middleware myLogger simplesmente imprime uma mensagem e passa a solicitação para a próxima função de middleware na pilha chamando a função next () .


  1. Esta publicação conterá apenas o middleware myLogger; para publicações posteriores, você pode acessar o guia original do expressjs aqui .

Suraj Jain
fonte
1
Explicação muito boa.
Drumbeg
Está disponível no site expresso aqui expressjs.com/en/guide/writing-middleware.html , é realmente bom. Eu me pergunto por que ninguém mencionou isso até agora.
Suraj Jain #:
2
Agradável. É a explicação mais clara que eu já vi aqui e sim, estranho que ninguém tenha feito referência a ela!
21318 Drumbeg
1
Bem explicado
Rehan Shikkalgar
A ordem de carregamento do middleware é importante: as funções do middleware carregadas primeiro também são executadas primeiro. : Esta é uma nota tão importante. Nenhuma outra resposta menciona isso. Para um iniciante que trabalhou apenas em python, isso é extremamente importante, pois essas coisas podem nunca ter sido encontradas.
Tessaracter
11

===== Explicação muito, muito simples =====

Middlewares são freqüentemente usados ​​no contexto da estrutura Express.js. e são um conceito fundamental para o node.js. Em poucas palavras, é basicamente uma função que tem acesso aos objetos de solicitação e resposta do seu aplicativo. A maneira como eu gostaria de pensar sobre isso é uma série de 'verificações / pré-telas' pelas quais a solicitação passa antes de ser tratada pelo aplicativo. Por exemplo, Middlewares seria um bom ajuste para determinar se a solicitação é autenticada antes de prosseguir para o aplicativo e retornar a página de login se a solicitação não estiver autenticada ou para registrar cada solicitação. Estão disponíveis muitos middlewares de terceiros que permitem uma variedade de funcionalidades.

Exemplo simples de Middleware:

var app = express();
app.use(function(req,res,next)){
    console.log("Request URL - "req.url);
    next();
}

O código acima seria executado para cada solicitação que chegasse e registraria o URL da solicitação, o método next () essencialmente permite que o programa continue. Se a função next () não for invocada, o programa não continuará mais e interromperá na execução do middleware.

Algumas dicas do Middleware:

  1. A ordem dos middlewares em seu aplicativo é importante, pois a solicitação passaria por cada um em uma ordem seqüencial.
  2. Esquecer de chamar o método next () em sua função de middleware pode interromper o processamento de sua solicitação.
  3. Qualquer alteração nos objetos req e res na função middleware tornaria a alteração disponível para outras partes do aplicativo que usam req e res
Vaibhav Bacchav
fonte
1
Muito obrigado! esta é a melhor explicação até agora para entender isso. Uma pergunta, eu estou lendo algum código com middleware e ele não chama next()mas return next(). Qual é a diferença?
KansaiRobot
Muito obrigado amigo por palavras gentis ... nós fazemos next()porque queremos que o próximo middleware seja chamado, acho que next()ou não return next()deve fazer diferença! Ainda assim, depende do que o código é ...
Vaibhav Bacchav
7

Middlewares são funções executadas no meio depois que a entrada / fonte produz uma saída que pode ser a saída final ou pode ser usada pelo próximo middleware até que o ciclo esteja completo.

É como um produto que passa por uma linha de montagem onde é modificado à medida que avança até ser concluído, avaliado ou rejeitado.

Um middleware espera que algum valor trabalhe (ou seja, valores de parâmetro) e, com base em alguma lógica, o middleware chamará ou não chamará o próximo middleware ou enviará uma resposta de volta ao cliente.

Se você ainda não consegue entender o conceito de middleware, ele é semelhante aos padrões do Decorator ou da Cadeia de comando.

naz
fonte
5

Middleware é um subconjunto de funções encadeadas chamadas pela camada de roteamento js Express antes que o manipulador definido pelo usuário seja chamado. As funções de middleware têm acesso total aos objetos de solicitação e resposta e podem modificar qualquer um deles.

A cadeia de middleware é sempre chamada na ordem exata em que foi definida; portanto, é vital que você saiba exatamente o que uma parte específica do middleware está fazendo.
Quando uma função de middleware termina, chama a próxima função na cadeia, chamando seu próximo argumento como função.
Depois que a cadeia completa é executada, o manipulador de solicitações do usuário é chamado.

rishabh dev
fonte
1

Mantenha as coisas simples, cara!

Nota: a resposta está relacionada aos casos de middlware integrados ao ExpressJS, no entanto, existem diferentes definições e casos de uso de middlewares.

Do meu ponto de vista, o middleware atua como funções de utilitário ou auxiliar, mas sua ativação e uso são totalmente opcionais , usando o app.use('path', /* define or use builtin middleware */)que não queremos de nós para escrever algum código para realizar tarefas muito comuns necessárias para cada solicitação HTTP de nosso cliente como processar cookies, tokens CSRF e ..., que são muito comuns na maioria dos aplicativos, para que o middleware possa nos ajudar a fazer tudo isso para cada solicitação HTTP de nosso cliente em alguma pilha, sequência ou ordem de operações e fornecer o resultado do processo como uma única unidade de solicitação do cliente .

Exemplo:

Aceitar solicitações de clientes e fornecer respostas de volta a elas de acordo com suas solicitações é a natureza da tecnologia de servidor da web.

Imagine se estamos fornecendo uma resposta com apenas "Olá, mundo!" o texto para uma solicitação GET HTTP para o URI raiz do nosso servidor da Web é um cenário muito simples e não precisa de mais nada, mas se estiver verificando o usuário atualmente conectado e respondendo com "Olá, nome de usuário!" precisa de algo mais do que o habitual. Nesse caso, precisamos de um middleware para processar todos os metadados da solicitação do cliente e nos fornecer as informações de identificação obtidas da solicitação do cliente. De acordo com essa informação, podemos identificar exclusivamente nosso usuário atual e é possível responder a ele / ela com alguns dados relacionados.

Espero que ajude alguém!

MNR
fonte
-1

Em termos muito básicos, se eu quiser explicá-lo dessa maneira, eu aprendo isso no curso travado expresso do traversymedia youtube channel.
ok, então o middle ware é uma função que é executada depois que você faz uma chamada para sua rota dessa maneira.

var logger = function(req, res, next){
   console.log('logging...');
   next();
}

app.use(logger);

Essa função de logger é executada toda vez que você atualiza sua página, o que significa que você pode escrever qualquer coisa nela que você precise fazer depois que sua página for renderizada qualquer chamada da API de operação, redefinir as coisas basicamente qualquer coisa. e coloque esse middleware antes que sua ordem de função de rota seja realmente importante ou não funcione

Akshay Vinchurkar
fonte