Fork me on GitHub

7. Хитрости в Jade и свои страницы ошибок в Express

Добро пожаловать в седьмую часть руководства по созданию веб-приложения с помощью Node.js. В рамках серии уроков будет рассказано про основные особенности и трудности, которые возникают при работе с Node.js.

Предыдущие части:

7.1. Версии node.js пакетов

Для установки пакетов мы использовали npm, который настраивает пути таким образом, что пакет может быть загружен с указанием конкртеной версии. Чтобы установить пакет конкретной версии, необходимо выполнить:

npm install express@1.0.0

Чтобы использовать установленную версию, необходимо делать так:

var express = require('express@1.0.0');

Убедиться в работоспособности такого подхода легко — достаточно выполнить выше указанную строчку в консоли node:

$ node
> express = require('express@1.0.0')
{ version: '1.0.0'
, Server: { [Function: Server] parseQueryString: [Function] }
, createServer: [Function]
}

7.2. Хитрости в Jade

При изначальной реализации jade-шаблонов я жестко прописал все атрибуты. Однако, есть более лугкий путь — запись селекторов в виде сокращений классов и идентификаторов:

div#left.outline-view
  div#DocumentTitles
    ul#document-list
      - for (var d in documents)
        li
          a(id='document-title-' + documents[d].id, href='/documents/' + documents[d].id)
            =documents[d].title

Обратите внимание, что ID объединен с названием класса: div#left.outline-view.

В jade тэг по-умолчанию — это div, что означает, что предыдущий пример может быть переписан следующий образом:

#left.outline-view
  #DocumentTitles
    ul#document-list
      - for (var d in documents)
        li
          a(id='document-title-' + documents[d].id, href='/documents/' + documents[d].id)
            =documents[d].title

7.3. Страницы ошибок

Express позволяет определять «свои» обработчики ошибок с помощью app.error:

// Определение ошибки
function NotFound(msg) {
  this.name = 'NotFound';
  Error.call(this, msg);
  Error.captureStackTrace(this, arguments.callee);
}

sys.inherits(NotFound, Error);

// Этот метод приведет к отображению 500-ой ошибки
app.get('/bad', function(req, res) {
  unknownMethod();
});

app.error(function(err, req, res, next) {
  if (err instanceof NotFound) {
    res.render('404.jade', { status: 404 });
  } else {
    next(err);
  }
});

app.error(function(err, req, res) {
  res.render('500.jade', {
    status: 500,
    locals: {
      error: err
    }
  });
});

Обработчик ощибки принимает 4 параметра: error, req, res, и next. next позволяет передать управление следующему обработчику ошибок. В приведенном выше примере, обработчик 404-ой ошибки передает управление дальше, если ошибка не является NotFound, что приводит к тому, что все остальные ошибки ловятся в обработчике 500-ой ошибки.

Если перейти в браузере по адресу /bad, то в результате получим нашу страницу 500-ой ошибки. Обратите внимание, что я явно указываю код HTTP-ответа в настройках метода render — это очень важно. В противном случае, вместо ошибок 404 или 500 будет возвращаться код 200, обозначющий, что «всё хорошо».

7.4. Обработка ошибок в Mongoose

Функция next доступна во всех HTTP-методах нашего приложения, что означает, что мы можем им воспользоваться для показа «своей» 404-ой ошибки:

app.get('/documents/:id.:format?/edit', loadUser, function(req, res, next) {
  Document.findById(req.params.id, function(d) {
    if (!d) return next(new NotFound('Document not found'));
    // Иначе — отрисовать текущий шаблон …
  });
})

При использовании Mongoose это наиболее читабельный вариант генерации «своих» ошибок. Если просто выбросить исключение (throw new NotFound), то приложение упадет вместо вызова обработчика исключений.

7.5. Заключение

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

Express позволяет достаточно легко определять «свои» обработчики ошибок с помощью шаблонов, но очень важно не забывать указывать HTTP код ответа и использовать next(exception) в функциях обратного вызова.

Текущая версия Nodepad доступна в коммите 929f564.