Экспресс следующая функция, для чего она на самом деле?

124

Пытались найти хорошее описание того, что next()делает этот метод. В документации Express говорится, что next('route')можно использовать для перехода к этому маршруту и ​​пропустить все маршруты между ними, но иногда nextвызывается без аргументов. Кто-нибудь знает хороший учебник и т. Д., Который описывает nextфункцию?

Андреас Селенуолл
источник

Ответы:

161

next()без аргументов говорит: «Шучу, я на самом деле не хочу с этим справляться». Он возвращается и пытается найти следующий подходящий маршрут.

Это полезно, например, если вы хотите иметь какой-то менеджер страниц с ярлыками URL-адресов, а также многое другое, но вот пример.

app.get('/:pageslug', function(req, res, next){
  var page = db.findPage(req.params.pageslug);
  if (page) {
    res.send(page.body);
  } else {
    next();
  }
});

app.get('/other_routes', function() {
  //...
});

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

Таким образом, next()без аргументов позволяет притвориться, что вы не обработали маршрут, чтобы что-то другое могло его подобрать.


Или счетчик посещений с app.all('*'). Это позволяет вам выполнить некоторый общий установочный код, а затем перейти к другим маршрутам, чтобы сделать что-то более конкретное.

app.all('*', function(req, res, next){
  myHitCounter.count += 1;
  next();
});

app.get('/other_routes', function() {
  //...
});
Алекс Уэйн
источник
Отличный ответ! Я видел и другое использование next, например, next (err) и next ('route'). У вас теперь их цель, когда вы хотите распространить ошибку и когда вы хотите перейти на определенный маршрут?
Андреас Селенуолл,
8
@AndreasSelenwall next('route')специфичен app.VERB()и используется, когда у маршрута есть несколько обратных вызовов для « обхода оставшихся обратных вызовов маршрута ». next(err)Используется для перехода к любому « промежуточному программному обеспечению ошибок » ( Eиз сообщения).
Джонатан Лоновски
5
Upvoted. Только за эту фразу: «Шучу, я не хочу с этим справляться», вы заставили меня понять, что я искал. Я видел много подобных вопросов и нашел решение в одной фразе.
Педро Баррос
8
Вызов next()без аргументов на самом деле не говорит системе «я не хочу обрабатывать это», он просто сообщает системе, что нужно продолжить обработку любых оставшихся промежуточных программ после того, как это будет выполнено. Это не состояние ошибки для вызова next(), это часть нормального потока. Если вы не звоните, next()никакие другие маршруты обрабатываться не будут.
d512 08
1
Я бы хотел, чтобы больше ответов на этом веб-сайте было написано для непрофессионала ... 'next () без аргументов говорит: "Шучу, я не хочу с этим справляться"' - Идеально подходит для новичков ... (@ d512 имеет лучше объяснение)
daCoda
129

В большинстве фреймворков вы получаете запрос и хотите вернуть ответ. Из-за асинхронной природы Node.js у вас возникают проблемы с вложенными обратными вызовами, если вы делаете нетривиальные вещи. Чтобы этого не происходило, в Connect.js (до версии 4.0 Express.js был слой поверх connect.js) есть нечто, называемое промежуточным программным обеспечением, которое представляет собой функцию с 2, 3 или 4 параметрами.

function (<err>, req, res, next) {}

Ваше приложение Express.js представляет собой набор этих функций.

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

Маршрутизатор особенный, это промежуточное программное обеспечение, которое позволяет вам выполнять одно или несколько промежуточных программ для определенного URL-адреса. Итак, это стек внутри стека.

Итак, что делать дальше? Просто он сообщает вашему приложению, что нужно запустить следующее промежуточное ПО. Но что происходит, когда вы переходите к следующему? Express прервет текущий стек и запустит все связующее ПО с 4 параметрами.

function (err, req, res, next) {}

Это промежуточное ПО используется для обработки любых ошибок. Мне нравится делать следующее:

next({ type: 'database', error: 'datacenter blew up' });

С этой ошибкой я, вероятно, скажу пользователю, что что-то пошло не так, и запишу настоящую ошибку.

function (err, req, res, next) {
   if (err.type === 'database') {
     res.send('Something went wrong user');
     console.log(err.error);
   }
};

Если вы изобразите свое приложение Express.js в виде стека, вы, вероятно, сможете сами исправить множество странностей. Например, когда вы добавляете промежуточное ПО для файлов cookie после маршрутизатора, имеет смысл, что ваши маршруты не будут иметь файлов cookie.

Pickels
источник
3
Где бы вы сохранили эту функцию анонимного ведения журнала?
dennismonsewicz
«Express прервет текущий стек и запустит все промежуточное ПО, имеющее 4 параметра». Мне было интересно, как express может запускать промежуточное ПО для точного обработчика ошибок. Спасибо!
Абхишек Агарвал,
75

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

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

app.get('/user/:id', function (req, res, next) {
    console.log('before request handler');
    next();
});

app.get('/user/:id', function (req, res, next) {
    console.log('handling request');
    res.sendStatus(200);
    next();
});

app.get('/user/:id', function (req, res, next) {
    console.log('after request handler');
    next();
});

app.listen(3000, function () {
    console.log('Example app listening on port 3000!')
});

Если вы это сделаете

curl http://localhost:3000/user/123

вы увидите это на консоли:

before request handler
handling request
after request handler

Теперь, если вы закомментируете вызов next()в среднем обработчике следующим образом:

app.get('/user/:id', function (req, res, next) {
    console.log('handling request');
    res.sendStatus(200);
    //next();
});

Вы увидите это на консоли:

before request handler
handling request

Обратите внимание, что последний обработчик (тот, который печатает after request handler ) не запускается. Это потому, что вы больше не говорите Express, что нужно запустить следующий обработчик.

Так что на самом деле не имеет значения, был ли ваш «основной» обработчик (тот, который возвращает 200) успешным или нет, если вы хотите, чтобы остальные промежуточные программы работали, вы должны вызвать next().

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

app.get('/user/:id', function (req, res, next) {
    try {
       // ...
    }
    catch (ex) {
       // ...
    }
    finally {
       // go to the next handler regardless of what happened in this one
       next();
    }
});

app.get('/user/:id', function (req, res, next) {
    logToDatabase(req);
    next();
});

Если вы хотите, чтобы второй обработчик запустился, вы должны вызвать next()первый обработчик.

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

D512
источник
Sonfar лучший ответ для меня.
Норайр Гукасян
Хорошо объяснение!
Чанг
7

next () без параметра вызывает следующий обработчик маршрута ИЛИ следующее промежуточное ПО в структуре.

kyasar
источник
2
Или следующее промежуточное ПО.
robertklep
1

Это просто означает передачу управления следующему обработчику.

ура

мамаша
источник
1

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

Hukmaram
источник
0

Также задан вопрос об использовании следующего ('маршрута'), который, как представляется, до сих пор рассматривается в течение недели в предоставленных ответах:

  1. ИСПОЛЬЗОВАНИЕ next ():

Вкратце: следующая функция промежуточного программного обеспечения.

Выдержка из этой официальной документации Express JS - страница 'writing-middleware' :

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

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)

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

  1. ИСПОЛЬЗОВАНИЕ next ('route'):

Вкратце: следующий маршрут (по сравнению со следующей функцией промежуточного программного обеспечения в случае next ())

Выдержка из документации Express JS - страница using-middleware :

"Чтобы пропустить остальные функции промежуточного программного обеспечения из стека промежуточного программного обеспечения маршрутизатора, вызовите next ('route'), чтобы передать управление следующему маршруту . ПРИМЕЧАНИЕ: next ('route') будет работать только в функциях промежуточного программного обеспечения, которые были загружены с помощью app.METHOD () или router.METHOD ().

В этом примере показан вложенный стек промежуточного программного обеспечения, который обрабатывает запросы GET к пути / user /: id ".

app.get('/user/:id', function (req, res, next) {
  // if the user ID is 0, skip to the next route
  if (req.params.id === '0') next('route')
  // otherwise pass the control to the next middleware function in this stack
  else next()
}, function (req, res, next) {
  // render a regular page
  res.render('regular')
})

// handler for the /user/:id path, which renders a special page
app.get('/user/:id', function (req, res, next) {
  res.render('special')
})
Ула
источник
0

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

app.get ('/', (req, res, next) => {next ()});

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

next () fn необходимо вызывать в каждой функции промежуточного программного обеспечения, когда несколько функций промежуточного программного обеспечения передаются в app.use или app.METHOD, иначе следующая функция промежуточного программного обеспечения не будет вызываться (если передано более 1 функции промежуточного программного обеспечения). Чтобы пропустить вызов оставшихся функций промежуточного программного обеспечения, вызовите next ('route') внутри функции промежуточного программного обеспечения, после чего никакие другие функции промежуточного программного обеспечения не должны вызываться. В приведенном ниже коде будет вызываться fn1 и также будет вызываться fn2, поскольку next () вызывается внутри fn1. Однако fn3 не будет вызываться, поскольку next ('route') вызывается внутри fn2.

app.get('/fetch', function fn1(req, res, next)  {
console.log("First middleware function called"); 
    next();
}, 
function fn2(req, res, next) {
    console.log("Second middleware function called"); 
    next("route");
}, 
function fn3(req, res, next) {
    console.log("Third middleware function will not be called"); 
    next();
})
user3022150
источник