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

Уроки React . Урок 10.

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

Уроки React. Урок 4. Домашнее Задание.

Поговорим о нашем домашнем задании. Стоит отметить что при разработке decorators/mixins вся логика в большинстве случаев работает прекрасно. Она была реализована нами в классе, для выполнения домашнего задания оставалось вынести ее в decorator и соответствующий mixin. Так будет выглядеть наш decorator:

Leave a Reply