Этот справочник нужен для разбора приложения на Express 3.x. Его сигнатуры и встроенные модули Connect отличаются от поддерживаемых версий: Express 2.x и 3.x больше не получают исправлений. Примеры старых зависимостей не предназначены для нового публичного сервера. Для переноса используйте миграцию 3 → 4 и затем 4 → 5.
Начало работы
Предполагается, что node уже установлен (скачать). Давайте создадим первое приложение, для этого создайте директорию где-нибудь на своей машине:
$ mkdir hello-world
В этой папке вы создадите своё приложение в виде "пакета", это
обыкновенный node-овский пакет. Вам понадобится создать файл package.json
в своей папке. Для сопоставления с сохранённым деревом зависимостей ниже явно указана историческая 3.0.0beta7; это не поддерживаемая версия для нового сервиса. Значение npm info express version показывает текущий релиз и не подбирает совместимую версию к старому примеру. Изучение beta-версии допускается только в изолированной среде.
{
"name": "hello-world",
"description": "hello world test app",
"version": "0.0.1",
"private": true,
"dependencies": {
"express": "3.0.0beta7"
}
}
Теперь, когда у вас в папке есть package.json, можно воспользоваться
npm(1) для установки зависимостей, в частности
Express:
$ npm install
Как только npm отработает, в папке ./node_modules появится
локально установленный пакет Express 3.x. С помощью npm ls
в этом можно убедиться, вы увидите вот такое дерево
зависимостей.
$ npm ls
hello-world@0.0.1 /private/tmp
└─┬ express@3.0.0beta7
├── commander@0.6.1
├─┬ connect@2.3.9
│ ├── bytes@0.1.0
│ ├── cookie@0.0.4
│ ├── crc@0.2.0
│ ├── formidable@1.0.11
│ └── qs@0.4.2
├── cookie@0.0.3
├── debug@0.7.0
├── fresh@0.1.0
├── methods@0.0.1
├── mkdirp@0.3.3
├── range-parser@0.0.4
├─┬ response-send@0.0.1
│ └── crc@0.2.0
└─┬ send@0.0.3
└── mime@1.2.6
Пора создать само приложение! Создайте файл app.js или server.js,
имя может быть любым, подключите express, а затем создайте экземпляр приложения с помощью express():
var express = require('express');
var app = express();
Теперь, когда приложение создано, можно начинать определять маршруты с помощью app.МЕТОД(),
в данном случае на запрос "GET /" попытаемся ответить строкой "Hello World". req и
res - это те же самые объекты, которые нам предоставляет node, поэтому можно
пользоваться привычными res.end(), req.on('data', callback) и всё, что можно сделать
без использования Express.
app.get('/hello.txt', function(req, res){
var body = 'Hello World';
res.setHeader('Content-Type', 'text/plain');
res.setHeader('Content-Length', body.length);
res.end(body);
});
Express дополняет эти объекты и даёт нам высокоуровневые методы,
например, res.send(), который, кроме прочего,
автоматически добавляет заголовок Content-Length:
app.get('/hello.txt', function(req, res){
res.send('Hello World');
});
Теперь, чтобы принимать соединения, вызовите метод app.listen(),
который принимает такие же аргументы, что и node-овский net.Server#listen():
app.listen(3000);
console.log('Listening on port 3000');Использование express(1) для генерации приложения
Express поставляется с исполняемым файлом express(1).
Если с помощью npm Express установлен глобально, эта команда будет доступна
отовсюду:
$ npm install -g express
Этот инструмент упрощает создание скелета приложения,
но круг его задач узок. Например, он поддерживает не так уж много шаблонизаторов,
тогда как сам Express поддерживает вообще любые шаблонизаторы для node.
Обязательно почитайте --help:
Usage: express [options]
Options:
-h, --help показать эту справку
-V, --version показать номер версии
-s, --sessions добавить поддержку сессий
-e, --ejs использовать шаблонизатор ejs (по умолчанию используется jade)
-J, --jshtml использовать шаблонизатор jshtml (по умолчанию используется jade)
-H, --hogan использовать шаблонизатор hogan.js
-c, --css использовать CSS-движок (less|stylus) (по умолчанию используется простой CSS)
-f, --force выполнить принудительно, если директория непустаяЕсли надо сгенерировать приложение с EJS, Stylus и поддержкой сессий, можно просто выполнить:
$ express --sessions --css stylus --ejs myapp
create : myapp
create : myapp/package.json
create : myapp/app.js
create : myapp/public
create : myapp/public/javascripts
create : myapp/public/images
create : myapp/public/stylesheets
create : myapp/public/stylesheets/style.styl
create : myapp/routes
create : myapp/routes/index.js
create : myapp/views
create : myapp/views/index.ejs
install dependencies:
$ cd myapp && npm install
run the app:
$ node app
Как для любого другого node-приложения, нам понадобится установить зависимости:
$ cd myapp
$ npm install
Запускаем!
$ node app
Вот и всё, что необходимо для создания и запуска простейшего приложения. Не забывайте, что Express не привязан к какой-либо структуре директорий, это просто прототип, на который можно опираться в начале. Приложения различной структуры показаны в примерах в github-репозитории.
Обработка ошибок
Прослойки для обработки ошибок определяются, как и любые другие прослойки,
но с четырьмя аргументами, в таком виде
(err, req, res, next):
app.use(function(err, req, res, next){
console.error(err.stack);
res.send(500, 'Что-то сломалось!');
});
Хотя это и не обязательно, прослойки для обработки ошибок определяются
в самом низу, после всех остальных вызовов app.use(), как показано ниже:
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(function(err, req, res, next){
// логика
});
Из таких прослоек можно отдавать любые ответы. Можно отвечать HTML-страничкой с ошибкой, простым сообщением, JSON-строкой, чем угодно, на своё усмотрение.
Для лучшей организации высокоуровневого фреймворка, можно определять несколько прослоек обработки ошибок, как впрочем и других прослоек. Например, вам надо объявить один обработчик ошибок для запросов, сделанных с помощью XHR, другой - для обычных запросов. Вот как это можно сделать:
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(logErrors);
app.use(clientErrorHandler);
app.use(errorHandler);
Здесь logErrors может писать информацию о запросе
и ошибках в stderr или в loggly или подобные сервисы:
function logErrors(err, req, res, next) {
console.error(err.stack);
next(err);
}
Где clientErrorHandler определён, как показано ниже,
заметьте, что ошибка явным образом передаётся в next.
function clientErrorHandler(err, req, res, next) {
if (req.xhr) {
res.send(500, { error: 'Что-то стряслось!' });
} else {
next(err);
}
}
Перехватчик всех ошибок errorHandler может быть реализован так:
function errorHandler(err, req, res, next) {
res.status(500);
res.render('error', { error: err });
}Подсчёт строк User-Agent за минуту
В этой секции приложение считает уникальные строки User-Agent, замеченные за последнюю минуту. Это учебный пример временного окна в sorted set, а не число людей или сессий. Для хранения используется Redis. Прежде всего,
создайте файл package.json со всеми зависимостями - одна для клиента Redis,
другая - для Express. Далее, убедитесь, что Redis установлен
и запущен с помощью $ redis-server.
{
"name": "app",
"version": "0.0.1",
"dependencies": {
"express": "3.0.0beta7",
"redis": "*"
}
}
Теперь надо создать приложение и подключение к Redis:
var express = require('express');
var redis = require('redis');
var db = redis.createClient();
var app = express();
Следующая прослойка обновляет время последнего появления строки User-Agent. Упорядоченное множество позволяет выбрать строки, замеченные за последние N миллисекунд. Для этого мы передаём отметку времени в качестве весового коэффициента элемента множества. Обратите внимание, что мы используем User-Agent вместо нормального ID пользователя.
app.use(function(req, res, next){
var ua = req.headers['user-agent'] || '(отсутствует)';
db.zadd('online', Date.now(), ua, next);
});
Следующая прослойка получает строки User-Agent, замеченные за последнюю минуту, используя zrevrangebyscore
для выборки с max = плюс-бесконечность,
так что выбираются элементы, отметка времени которых попадает в последнюю минуту, ограниченных
min = текущее время - 60000 миллисекунд.
app.use(function(req, res, next){
var min = 60 * 1000;
var ago = Date.now() - min;
db.zrevrangebyscore('online', '+inf', ago, function(err, users){
if (err) return next(err);
req.online = users;
next();
});
});
Запустите пример только в локальном изолированном окружении. Два запроса с одинаковым User-Agent должны оставлять один элемент, а запросы с двумя разными строками — два, пока обе записи попадают в минутное окно. Запрос с отсутствующим заголовком попадает в одну общую тестовую группу. Это проверяет модель ключа, а не идентификацию людей; реальному приложению также нужна очистка старых записей.
app.get('/', function(req, res){
res.send(req.online.length + ' уникальных User-Agent за минуту');
});
app.listen(3000);Express через прокси
Express может читать сведения от реверс-прокси, но настройка доверия не проверяет подлинность самих заголовков. Исторический app.enable('trust proxy') разрешал использовать X-Forwarded-*; он безопасен только при контролируемом пути запроса, где клиент не может обратиться к приложению напрямую, а последний доверенный прокси перезаписывает эти поля. Для текущего Express задавайте точные доверенные узлы по своей топологии, а не включайте общий флаг из примера.
Есть ещё несколько небольших эффектов, вызываемых включением этой настройки. Во-первых,
через заголовок X-Forwarded-Proto прокси может сообщить
приложению, протокол - HTTPS или HTTP. Это значение доступно через
req.protocol.
Второе изменение - это то, что значения req.ip
и req.ips заполняются из
списка адресов в X-Forwarded-For.
Исходная документация: © 2012 TJ Holowaychuk; русский перевод опубликован JSman. Технические уточнения обозначены отдельно от сигнатур Express 3.