Всем привет! Давайте продолжим наш урок об основах Express и Middleware
.
Итог (добавим в app.js
):
app.use(function(req, res, next) { if (req.url == '/') { res.end("Hello"); } else { next(); } });
Функция next
служить для того, чтобы передать управление дальше по цепочке к следующему Middleware
, то есть, к следующей функции, которая объявлена через app.use
. Второй Middleware
тоже может что-то проверить и передать управление дальше:
// Middleware app.use(function(req, res, next) { if (req.url == '/') { res.end("Hello"); } else { next(); } }); app.use(function(req, res, next) { if (req.url == '/test') { res.end("Test"); } else { next(); } });
Запустим вот таким образом и посмотрим, что у нас получилось.
http://localhost:3000/
http://localhost:3000/test
Все работает.
А что будет, если мы пойдем на страницу, которой не существует?
http://localhost:3000/nopage
Сработал встроенный обработчик Express. В том случае, если Middleware
кончились, next
вызван, а следующего Middleware
нет, то Express выводит страничку «не найдено» по умолчанию. Для того, чтобы как-то влиять на это, сделаем еще один Middleware
, который будет получать req
и res
, и который будет всегда замыкать цепочку:
app.use(function(req, res) { res.send(404, "Page Not Found Sorry"); });
Запустим это. Обратим внимание в console
, статус совершенно правильный – 404
. Здесь мы сейчас использовали метод res.send
. Он отсутствует в обычных req
и res
, но он есть в Express, потому что он, перед тем как вызвать цепочку Middleware
, расширяет объекты req
и res
при помощи наследования и добавляет им некоторые свои методы. Эти методы можно посмотреть на страничке expressjs.com. Там есть API Reference, где имеется много чего, в частности, нам нужно Response
и метод send
. Вот его простой вид: res.send(hello world);
– отослать строку, а есть и более сложные и интересные варианты:
res.send(new Buffer('whoop')); res.send({ some: 'json' }); res.send('<p>some html</p>'); res.send(404, 'Sorry, we cannot find that!'); res.send(500, { error: 'something blew up' }); res.send(200);
Send
умеет посылать что угодно: Buffer
, json
, текст, и если первый аргумент – это число, то он ставит соответствующий статус тоже. Такой вот универсальный и удобный метод.
Что будет, если где-то произойдет ошибка? Давайте создадим специальный Middleware
, назовем его error
, и в нем будет ошибка:
app.use(function(req, res, next) { if (req.url == '/error') { BLABLA() } else { next(); } });
Зайдем на :
http://localhost:3000/error
Сработал встроенный обработчик ошибок Express. Он работает в том случае, если в Middleware
есть throw
.
app.use(function(req, res, next) { if (req.url == '/error') { throw new Error ('......') } else { next(); } });
Конечно, он не сработает, если этот throw
завернут в setTimeout
. Так уж устроен JavaScript.
Займемся более правильной обработкой ошибок вообще, тех, которые возникают в ходе нормального функционирования сайта. Например, человек зашел на url
, на который заходить не имеет права. В этом случае мы можем либо сразу же ему ответить (res.send(401)
), либо бывает гораздо удобнее передать ошибку дальше по цепочке. Выглядит это так (изменим нашу предыдущую функцию):
app.use(function(req, res, next) { if (req.url == '/forbidden') { next(new Error("wops, denied")); } else { next(); } });
Если в next
есть какой-то аргумент, тогда Express знает, что это ошибка, и передает ее обработчику ошибок. По умолчанию такой обработчик, как мы видели, выводит стек, что совершенно неприемлемо в реальной жизни. Поэтому можно задать свой обработчик. Он задается совершенно так же, как и Middleware
, а app.use
– только функция – не 3 элемента имеет, а 4:
app.use(function(err, req, res, next) {
В JavaScript у каждой функции есть свойство length
, которое содержит количество аргументов в ее объявлении, поэтому Express, если видит функцию с 4 аргументами, то оно может понять, что это обработчик ошибок. Соответственно, если произошла ошибка либо throw
, либо next
вызвался с аргументом, тогда управление передается сразу в
app.use(function(err, req, res, next) { }
Здесь мы уже можем вывести ошибку, если это разработка – то вывести stack
, если это реальная жизнь – код ошибки, шаблон и т.д.
Как нам узнать в скрипте сейчас разработка или реальный боевой запуск? Для этого есть специальное значение, которое можно получить app.get('env')
. Если не указана специальная переменная окружения NODE_ENV
, то эта штука равна development
. А если она указана, то остается равна значению этой переменной:
app.use(function(err, req, res, next) { // NODE_ENV = 'production' if (app.get('env') == 'development') {
В реальной жизни в боевом запуске она имеет значение production
. Соответственно, если это development
, то давайте выведем ошибку красиво. Для этого есть специальная встроенная Middleware
– express.errorHandler
. Возьмем ее из cгенерированного шаблона и поставим вот сюда:
app.use(function(err, req, res, next) { // NODE_ENV = 'production' if (app.get('env') == 'development') { app.use (express.errorHandler()); } });
Что это за зверь такой? Давайте посмотрим внимательнее в исходники Express. В том, что экспортирует Express нет errorHandler
. Чтобы его найти нам надо немного глубже заглянуть в то, что здесь происходит, а именно, в цикл:
for (var key in connect.middleware) { Object.defineProperty( exports , key , Object.getOwnPropertyDescriptor(connect.middleware, key)); }
Еxpress – это фреймворк, который создан вокруг другого фреймворка, который называется connect
. (c версии Express 4 это стало не так, но наш урок построен на версии Express 3). В нем есть различные Middleware
, которые по умолчанию Express таким образом в себя получает. Middleware
можно посмотреть в
node modules→connect→ lib→middleware →errorHandler.
Теперь создадим errorHandler
и отдадим ему запрос в явном виде, так как предыдущий код, к сожалению, работать не будет:
app.use(function(err, req, res, next) { // NODE_ENV = 'production' if (app.get('env') == 'development') { var errorHandler = express.errorHandler(); errorHandler(err, req, res, next); } else { res.send(500); } });
Проверим.У нас development
, поэтому сработала соответствующая ветка if
.
В следующих статьях мы продолжим работать с Express, рассмотрим встроенные Middleware
и выведем нормальную html
-страничку.
Код урока доступен по ссылке.
Материалы для статьи взяты из данного скринкаста.
We are looking forward to meeting you on our website soshace.com