24Nov

expess_1_2
Всем привет! Давайте продолжим наш урок об основах 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-страничку.

Код урока доступен по ссылке.

keep-calm-and-express-yourself-445
Материалы для статьи взяты из данного скринкаста.

We are looking forward to meeting you on our website soshace.com

16. Уроки Node.js. Событийный цикл, библиотека libUV. Часть 1.

Всем привет. Если вы привыкли глубоко вникать в происходящее, то эта статья для вас. Здесь мы разберем те вопросы, которые рано или поздно обязательно возникнут при разработке, и ответа на которые требует глубокого понимания, как именно работает Node.js. Например, здесь (serverAsync.js смотрите файлы нашего предыдущего урока) для чтения файла использован асинхронный вызов:

Уроки Express.js . Логгер, Конфигурация, Шаблонизация с EJS. Часть 2.

Favicon – это все connect Middleware, он смотрит, если url имеет вид favicon.ico, то он читает favicon и выдает, а иначе передает управления дальше. Логгер выводит запись о том, что у нас за запрос пришел. Например, если сейчас запустить приложение, то логгер что-то выведет, если мы зайдем на:

Доклад. Agile (вводная часть). Scrum

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

Leave a Reply