Если вы использовали какие-либо веб-фреймворки Node.js (такие как Express или Restify) до того, как вы, вероятно, использовали множество модулей промежуточного программного обеспечения, но создавали ли вы их раньше? Если вы уже создавали его раньше, вам когда-нибудь приходилось замыкать цепочку обработки запросов, блокируя выполнение следующего модуля промежуточного программного обеспечения и возвращая собственный ответ? Если это так, вы, возможно, столкнулись с той же проблемой, с которой я боролся в течение довольно долгого времени.

Я создал несколько модулей промежуточного программного обеспечения, специально привязанных к Restify как базовой веб-инфраструктуре, работающей с Node.js. В некоторых из этих модулей мне нужно было разорвать цепочку обработки запросов и вернуть собственный ответ. Однако долгое время я делал это не совсем правильно. Давайте посмотрим на примере того, что я делал:

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

Другая проблема, к которой это приводит, заключается в том, что он выполнит два экземпляра res.send(), и это вызовет ошибку с указанием "can't set headers after they are sent". Причина этого в том, что мы пытаемся установить эти заголовки с первым экземпляром res.send() в нашем модуле промежуточного программного обеспечения, а затем, поскольку мы не блокируем выполнение реализации маршрута, мы пытаемся использовать res.send() во второй раз.

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

Обычно вы передаете ошибку функции next(), чтобы сигнализировать об обрыве в цепочке обработчиков (например, next(new Error('some error message');, но в этом случае у нас не обязательно есть ошибка, и мы скорее просто обработаем все сами. Я упустил из виду возможность этой опции использовать false в качестве значения в документации, в которой конкретно указано:

Вы можете передать значение false не для ошибки, а для остановки цепочки обработчиков. Это полезно, если у вас был res.send в раннем фильтре, что не является ошибкой, и, возможно, у вас есть более поздний, который вы хотите закоротить.

Первоначально опубликовано на clarkio.com 2 ноября 2016 г.