Что в действительности означает middleware и app.use в Expressjs?


228

Почти каждое приложение Express, которое я вижу, имеет app.useутверждение для промежуточного программного обеспечения, но я не нашел четкого и краткого объяснения того, что такое промежуточное программное обеспечение на самом деле и что делает это app.useутверждение. Даже сами экспресс-документы немного расплывчаты в этом. Можете ли вы объяснить эти понятия для меня, пожалуйста?


3
аналогичный вопрос для справки (хотя этот был создан ранее): stackoverflow.com/questions/11321635/…
ericsoco

43
^ Ха! Эти два вопроса ссылаются друг на друга в комментариях.
Джулиан Х. Лэм

17
Так что это циркулярная ссылка.
Стив К

6
Express.js Middleware Demysified Отличное сообщение в блоге на эту тему. Это было скопировано здесь ранее, что, конечно, является плагиатом, но оригинальный пост все еще очень полезен, поэтому я оставляю здесь ссылку.
Тотимедли

1
Я написал статью о промежуточном программном обеспечении express.js. Вот ссылка: nodexplained.com/blog-detail/2017/12/31/…
shrawan_lakhe

Ответы:


111

промежуточный слой

Я на полпути к разделению концепции промежуточного программного обеспечения в новом проекте.

Промежуточное программное обеспечение позволяет вам определять стек действий, которые вы должны выполнять. Экспресс-серверы сами по себе представляют собой связующее ПО.

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

Затем вы можете добавить слои в стек промежуточного программного обеспечения, вызвав .use

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

Уровень в стеке промежуточного программного обеспечения - это функция, которая принимает n параметров (2 для экспресс-функции, req& res) и nextфункцию.

Промежуточное программное обеспечение ожидает, что слой выполнит некоторые вычисления, увеличит параметры и затем вызовет next.

Стек ничего не делает, если вы не справитесь с этим. Express будет обрабатывать стек каждый раз, когда входящий HTTP-запрос перехватывается на сервере. С промежуточным ПО вы обрабатываете стек вручную.

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

Более полный пример:

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
})

В экспресс-выражениях вы просто определяете стек операций, которые вы хотите, чтобы экспресс обрабатывал для каждого входящего HTTP-запроса.

С точки зрения экспресса (а не соединения) у вас есть глобальное промежуточное ПО и промежуточное ПО для конкретных маршрутов. Это означает, что вы можете присоединить стек промежуточного программного обеспечения к каждому входящему HTTP-запросу или только к HTTP-запросам, которые взаимодействуют с определенным маршрутом.

Расширенные примеры экспресс и промежуточного программного обеспечения:

// 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); 
});

4
Хм ... промежуточное программное обеспечение в этом случае ваша собственная библиотека или часть экспресс?
ИЗ.

5
Прохладно. Я все еще немного смущен app.use()синтаксисом. Какова реальная возвращаемая стоимость промежуточного программного обеспечения и что useс ним делать?
ИЗ.

9
Использование @iZ добавляет его в стек. Затем каждый запрос проходит через стек.
Рэйнос

7
@Raynos, ссылка на ваш проект, «middleware», не работает.
Ли

1
@Raynos, но я вижу, что промежуточное ПО все еще используется в Express? что ты имеешь в виду, что это ядерное оружие?
Тимо Хуовинен

60

После упрощения веб-сервер можно рассматривать как функцию, которая принимает запрос и выводит ответ. Таким образом, если вы рассматриваете веб-сервер как функцию, вы можете организовать его на несколько частей и разделить их на более мелкие функции, чтобы их композиция была исходной функцией.

Промежуточные программы - это небольшие функции, которые вы можете создавать вместе с другими, и очевидным преимуществом является то, что вы можете использовать их повторно.


33

Я добавляю поздний ответ, чтобы добавить что-то, не упомянутое в предыдущих ответах.

К настоящему времени должно быть ясно, что промежуточное ПО выполняет функции, выполняемые между запросом клиента и ответом сервера . Наиболее распространенные функции промежуточного программного обеспечения: управление ошибками, взаимодействие с базой данных, получение информации из статических файлов или других ресурсов. Для перемещения по стеку промежуточного программного обеспечения должен быть вызван следующий обратный вызов, вы можете увидеть его в конце функции промежуточного программного обеспечения, чтобы перейти к следующему шагу в потоке.

Вы можете использовать app.useподход , и есть поток , как это :

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');

но вы также можете использовать другой подход и передавать каждое промежуточное ПО в качестве аргументов функции. Вот пример с сайта MooTools Nodejs, где промежуточное ПО получает поток Twitter, Github и Blog перед responseотправкой обратно клиенту. Обратите внимание, как функции передаются в качестве аргументов в app.get('/', githubEvents, twitter, getLatestBlog, function(req, res){. Использование app.getбудет вызываться только для запросов GET, app.useбудет вызываться для всех запросов.

// 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
    });
});

2
Я искал ответ на вопрос, поддерживает ли Express.js монтирование промежуточного программного обеспечения на основе маршрута (НЕ на основе маршрутизатора)? Кажется, вы показали это в своем ответе.
Сельчук

Можете ли вы объяснить приведенный выше пример? Как вы можете передать так много функций в app.get (...) и в каком порядке они называются?
Таннер Саммерс

2
Привет @TannerSummers, .get()метод принимает 3 типа аргументов: первый, последний и средний. Внутренне он определяет, существует ли больше аргументов, чем 2, и использует их (средние) в качестве функций промежуточного программного обеспечения, вызывая их слева направо.
Серхио

22

У руководства expressjs есть довольно аккуратный ответ на ваш вопрос, я настоятельно рекомендую вам прочитать его, я выкладываю небольшой фрагмент руководства, руководство довольно хорошее.

Написание промежуточного программного обеспечения для использования в приложениях Express

обзор

Функции промежуточного программного обеспечения - это функции, которые имеют доступ к объекту запроса ( req ), объекту ответа ( res ) и следующей функции в цикле запрос-ответ приложения. Следующая функция - это функция в маршрутизаторе Express, которая при вызове выполняет промежуточное ПО, которое следует за текущим промежуточным ПО.

Функции промежуточного программного обеспечения могут выполнять следующие задачи:

  • Выполнить любой код.
  • Внесите изменения в запрос и объекты ответа.
  • Завершите цикл запрос-ответ.
  • Вызовите следующее промежуточное программное обеспечение в стеке.

Если текущая функция промежуточного программного обеспечения не завершает цикл запрос-ответ, она должна вызвать next (), чтобы передать управление следующей функции промежуточного программного обеспечения. В противном случае запрос останется висеть.

введите описание изображения здесь

пример

Вот пример простого приложения «Hello World» Express. В оставшейся части этой статьи будут определены и добавлены две функции промежуточного программного обеспечения для приложения: одна называется myLogger, которая печатает простое сообщение журнала, а другая - requestTime 1, которая отображает временную метку HTTP-запроса.

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

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

app.listen(3000)   

Функция промежуточного ПО myLogger

Вот простой пример функции промежуточного программного обеспечения под названием «myLogger». Эта функция просто печатает «LOGGED», когда через него проходит запрос к приложению. Функция промежуточного программного обеспечения назначается переменной с именем myLogger.

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

Обратите внимание на вызов выше к следующему () . Вызов этой функции вызывает следующую функцию промежуточного программного обеспечения в приложении. Функция next () не является частью Node.js или Express API, но является третьим аргументом, который передается в функцию промежуточного программного обеспечения. Функция next () может быть названа как угодно, но по соглашению она всегда называется «next». Чтобы избежать путаницы, всегда используйте это соглашение.

Чтобы загрузить функцию промежуточного программного обеспечения, вызовите app.use () , указав функцию промежуточного программного обеспечения. Например, следующий код загружает функцию промежуточного программного обеспечения myLogger перед маршрутом к корневому пути (/).

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)

Каждый раз, когда приложение получает запрос, оно выводит сообщение «LOGGED» на терминал.

Порядок загрузки промежуточного программного обеспечения важен: функции промежуточного программного обеспечения, которые загружаются первыми, также выполняются первыми.

Если myLogger загружается после маршрута к корневому пути, запрос никогда не достигает его, и приложение не выводит «LOGGED», потому что обработчик маршрута корневого пути завершает цикл запрос-ответ.

Функция промежуточного программного обеспечения myLogger просто печатает сообщение, а затем передает запрос следующей функции промежуточного программного обеспечения в стеке, вызывая функцию next () .


  1. Этот пост будет содержать только промежуточное программное обеспечение myLogger, для дальнейшего поста вы можете перейти к оригинальному руководству по expressjs здесь .


1
Очень хорошее объяснение.
Драмбег

Это доступно на экспресс-сайте здесь expressjs.com/en/guide/writing-middleware.html , это действительно хорошо. Интересно, почему никто не упомянул это до сих пор.
Сурадж Джейн

2
Хороший. Это самое ясное объяснение, которое я видел здесь, и да, странно, что никто не ссылался на него!
Драмбег

1
Красиво объяснил
Рехан Шиккалгар

Порядок загрузки промежуточного программного обеспечения важен: функции промежуточного программного обеспечения, которые загружаются первыми, также выполняются первыми. Это такая важная заметка. Ни один другой ответ не упоминает об этом. Для новичка, который работал только на python, это чрезвычайно важно, поскольку с такими вещами никогда не сталкивались.
Tessaracter

11

===== Очень очень простое объяснение =====

Промежуточное программное обеспечение часто используется в контексте платформы Express.js и является фундаментальной концепцией для node.js. Короче говоря, это в основном функция, которая имеет доступ к объектам запросов и ответов вашего приложения. Я бы хотел подумать об этом - это серия «проверок / предварительных проверок», через которые проходит запрос, прежде чем он будет обработан приложением. Например, Middlewares было бы целесообразно определить, аутентифицирован ли запрос до того, как он поступит в приложение, и вернуть страницу входа в систему, если запрос не аутентифицирован, или для регистрации каждого запроса. Доступно множество сторонних промежуточных программ, обеспечивающих различные функциональные возможности.

Простой пример Middleware:

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

Приведенный выше код будет выполняться для каждого входящего запроса и будет регистрировать URL-адрес запроса, метод next () по существу позволяет программе продолжаться. Если функция next () не вызывается, программа не будет продолжать работу и остановится при выполнении промежуточного программного обеспечения.

Несколько промежуточных программных Gotchas:

  1. Порядок промежуточного программного обеспечения в вашем приложении имеет значение, так как запрос будет проходить через каждого из них в последовательном порядке.
  2. Если вы забудете вызвать метод next () в вашей функции промежуточного программного обеспечения, это может остановить обработку вашего запроса.
  3. Любое изменение объектов req и res в функции промежуточного программного обеспечения сделает это изменение доступным для других частей приложения, использующего req и res.

1
Большое спасибо! это лучшее объяснение на данный момент. Вопрос, я читаю код с промежуточным слоем , и это не вызывает , next()но return next(). В чем разница?
KansaiRobot

Большое спасибо другу за добрые слова ... мы делаем это next()потому, что хотим, чтобы было вызвано следующее промежуточное ПО, я не думаю, next()или return next(), должно быть, что-то изменилось! Тем не менее, это зависит от того, что код ...
Vaibhav Bacchav

7

Промежуточное программное обеспечение - это функции, выполняемые посередине после того, как вход / источник генерирует выходной сигнал, который может быть конечным выходом или может использоваться следующим промежуточным программным обеспечением до завершения цикла.

Это похоже на продукт, который проходит через сборочную линию, где он изменяется по мере продвижения, пока не будет завершен, оценен или отклонен.

Промежуточное программное обеспечение ожидает, что какое-то значение будет работать (т.е. значения параметров), и на основе некоторой логики промежуточное программное обеспечение будет вызывать или не вызывать следующее промежуточное программное обеспечение или отправлять ответ клиенту.

Если вы все еще не можете понять концепцию промежуточного программного обеспечения, это похоже на шаблоны декоратора или цепочки команд.


5

Промежуточное программное обеспечение - это подмножество связанных функций, вызываемых слоем маршрутизации Express js до вызова пользовательского обработчика. Функции промежуточного программного обеспечения имеют полный доступ к объектам запросов и ответов и могут изменять любой из них.

Цепочка промежуточного программного обеспечения всегда вызывается в точном порядке, в котором она была определена, поэтому крайне важно, чтобы вы точно знали, что делает конкретная часть промежуточного программного обеспечения.
По завершении функции промежуточного программного обеспечения она вызывает следующую функцию в цепочке, вызывая ее следующий аргумент как функцию.
После выполнения всей цепочки вызывается обработчик пользовательских запросов.


1

Держите вещи простыми, чувак!

Примечание. Ответ относится к встроенным программным продуктам ExpressJS, однако существуют разные определения и варианты использования промежуточного программного обеспечения.

С моей точки зрения, промежуточный слой выступает в качестве полезных или вспомогательных функций , но его активация и использование полностью необязательно , используя app.use('path', /* define or use builtin middleware */)который не хочет от нас , чтобы написать код для выполнения очень общих задач , которые необходимы для каждого запроса HTTP нашего клиента например, обработка куки, токены CSRF и ..., которые очень распространены в большинстве приложений, поэтому промежуточное ПО может помочь нам сделать все это для каждого HTTP-запроса нашего клиента в некотором стеке, последовательности или порядке операций, а затем представить результат процесса как единая единица клиентского запроса .

Пример:

Прием запросов клиентов и предоставление ответных ответов на них в соответствии с их запросами является природой технологии веб-сервера.

Представьте, что мы отвечаем просто "Привет, мир!" Текст для запроса GET HTTP к корневому URI нашего веб-сервера является очень простым сценарием и больше ничего не требует, но вместо этого, если мы проверяем текущего пользователя, вошедшего в систему, а затем отвечаем «Hello, Username!» в этом случае нам нужно нечто большее, чем обычно, в этом случае нам нужно промежуточное программное обеспечение для обработки всех метаданных запроса клиента и предоставления нам идентификационной информации, полученной из запроса клиента, а затем в соответствии с этой информацией мы можем однозначно идентифицировать нашего текущего пользователя и получить возможность ответить на него / ее с некоторыми связанными данными.

Надеюсь, это поможет кому-то!


-1

В самом простом термине, если я хочу объяснить это так, я узнаю это из ускоренного курса traversymedia youtube channel.
Итак, промежуточное ПО - это функция, которая выполняется после того, как вы выполните вызов на ваш маршрут следующим образом.

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

app.use(logger);

Эта функция ведения журнала выполняется каждый раз, когда вы обновляете свою страницу, что означает, что вы можете написать в ней все, что вам нужно сделать после того, как на вашей странице будет обработан любой вызов API api, сбросить все, что угодно. и поместите это промежуточное ПО до того, как ваш порядок маршрутизации промежуточного ПО будет действительно важным, или он не будет работать

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.