Октябрь 2015

Том 30, номер 10

Работающий программист - MEAN: установка Express

Тэд Ньюард | Октябрь 2015

Стек MongoDB, Express, AngularJS, Node.js (MEAN) является альтернативным «веб-стеком» для стека ASP.NET, к которому привыкли .NET-разработчики.

Эта статья является третьей в серии, в которой я расскажу о библиотеке Express, которая обеспечивает HTTP-обработку на сервере. В прошлой статье (msdn.microsoft.com/magazine/mt422588) я показал, как установить приложение Node.js в Microsoft Azure. Поскольку эта операция в основном сводится к простой передаче в репозитарий Git (с последующей передачей в удаленный репозитарий Azure), я оставлю пока эту тематику, по крайней мере до тех пор, пока не начну рассказывать о других сервисах (вроде MongoDB) на платформе Azure. В качестве альтернативы можно запускать все примеры на локальных машинах, чтобы следовать за мной. Azure точно не требуется (во всяком случае, пока дело не дойдет до передачи кода в производственную среду).

Попасть на Express

Если отбросить все каламбуры, Express — это довольно простая библиотека. С ней легко работать, как только вы примете образ мышления, принятый в Node.js. Чтобы не давать чрезмерной познавательной нагрузки, я начну с нуля (фигурально выражаясь). Я буду исходить из предположения, что у вас есть совершенно новый сайт Azure (результат успешного выполнения команды «azure site create–git») и простое приложение Express, готовое к запуску.

В первой статье этой серии (msdn.microsoft.com/magazine/mt185576) я упоминал npm — Node Package Manager. Это диспетчер библиотек и зависимостей для всех Node-приложений. Его роль аналогична таковой для NuGet в мире Microsoft .NET Framework. По сути, оба они построены на идеях Rubygems, поэтому у них есть довольно много общих характеристик.

Оказывается, npm полагается на JSON-файл, содержащий все зависимости — пакеты для производственных сред и пакеты только для разработки. Вся информация хранится в одном файле — package.json. Поэтому логичный первый шаг — создать файл с Express в качестве зависимости, как показано на рис. 1.

Рис. 1. Создание файла с Express в качестве зависимости

{
  "name": "MSDN-MEAN",
  "version": "0.0.1",
  "description": "Testing out building a MEAN app from scratch",
  "main": "app.js",
  "scripts": {},
  "author": "Ted Neward",
  "license": "ISC",
  "dependencies": {
    "express": "^4.9.8",
    "lodash": "^2.4.1",
    "serve-static": "^1.7.0"
  },
  "devDependencies": {
  }
}

Содержимое этого файла по большей части понятно и без пояснений, но на некоторые моменты стоит обратить внимание. Во-первых, вы будете часто вести этот файл вручную (хотя есть некоторые утилиты, управляющие им за вас). Но мы будем придерживаться стиля «текстовый редактор и командная строка», свойственного менталитету в мире Node.js. В итоге потенциальные разработчики под Node должны чувствовать себя комфортно, редактируя все вручную несмотря на наличие каких-либо инструментов. Во-вторых, здесь присутствуют два набора зависимостей: dependencies (пакеты, которые npm должен устанавливать в среде производственного типа) и devDependencies (пакеты, предназначенные исключительно для разработчиков).

На данный момент самый простой вариант — считать, что dependencies являются зависимостями, которые будут установлены при передаче приложения (через Git) в Azure. В то же время devDependencies устанавливаются (наряду с содержимым своих зависимостей) при установке пакетов на лэптоп разработчика, как показано на рис. 2.

Установка ваших зависимостей
Рис. 2. Установка ваших зависимостей

И раз уж речь зашла об этом, вы должны заняться этим прямо сейчас. Располагая в текущем каталоге только файлом package.json введите в командной строке npm install и наблюдайте, как npm извлекает express, lodash (удобная библиотека функций и методов, включая некоторые функциональные средства вроде map и filter, а также расширения массивов и объектов) и serve-static (об этом позже) на ваш локальный компьютер.

Как и NuGet, npm устанавливает не просто пакет, но и все его зависимости. Как раз это и приводит к отображению дерева в терминале. В случае крупных объединенных пакетов, включающих большое количество популярных пакетов, это дерево может получиться весьма длинным. Утилита npm также замечает, что я исключил две записи в своем package.json: поле repository, откуда поступил этот пакет, и данные README. Эти сведения используются в основном для npm-пакетов, устанавливаемых в централизованную библиотеку npm. Я нахожу, что они не особенно подходят для приложения, но и наличие их никак не повредит, если вы предпочитаете всячески избегать предупреждений от npm.

По мере продолжения этой серии статей я буду добавлять дополнительные пакеты в package.json, поэтому вы должны периодически выполнять npm install для получения новых пакетов. Кстати, обратите внимание в выводе дерева для express, что пакет debug (который я использовал в прошлый раз) является зависимостью, но я не помещал его в файл package.json напрямую. Такая у меня привычка: мой файл package.json должен явно перечислять все зависимости, которыми я непосредственно пользуюсь в работе (в противоположность тем зависимостям, которые используются библиотеками, но напрямую никогда не вызываются). Так что добавьте его в package.json и выполните еще одну команду npm install:

"dependencies": {
  "debug": "^2.2.0",
  "express": "^4.9.8",
  "lodash": "^2.4.1",
  "serve-static": "^1.7.0"
},

Благодаря этому я знаю, какой версией debug я пользуюсь (в противоположность версии, применяемой Express), на тот случай, если разница станет важной. Кстати, традиционный способ установки какой-либо библиотеки (теперь, когда вам известно, что представляет собой формат файла) — выполнение команды npm install <package> --save. Аргумент --save заставляет npm модифицировать файл package.json (в противоположность простой установке без ее регистрации).

По сути, если вы выполните npm install express --save, то npm обновит запись express до новейшей версии (на момент написания этой статьи — 4.13.3), хотя она уже есть в файле package.json. Есть и третий способ, при котором используется другой пакет, yeoman, обеспечивающий все, что нужно для создания приложений Express, но моя цель отчасти состоит в том, чтобы вы поняли все «движущиеся детали» MEAN, поэтому описание третьего способа я оставлю на потом.

Hello, Express

После установки в Express мы напишем вездесущую программу «Hello World». И код в файле app.js (а именно он указан в package.json в записи main) воздает должное Богам Компьютерной Науки (рис. 3).

Рис. 3. Код для Hello World Express

// Загрузка модулей
var express = require('express');
var debug = require('debug')('app');

// Создание экземпляра express
var app = express();

// Настройка простого маршрута (route)
app.get('/', function (req, res) {
  debug("/ requested");
  res.send('Hello World!');
});

// Запуск сервера
var port = process.env.PORT || 3000;
debug("We picked up",port,"for the port");
var server = app.listen(port, function () {

  var host = server.address().address;
  var port = server.address().port;

  console.log(
    'Example app listening at http://%s:%s', host, port);
});

Первые две строки — вызовы require, которые вы видели в прошлой статье; именно так на данный момент Node.js загружает необходимые модули. Это изменится в ECMAScript 6, как только его спецификация будет ратифицирована и вступит в действие. Эти строки дают вам доступ к пакетам Express и debug соответственно. Модуль Express, извлекаемый require, на самом деле является функцией, которая при вызове передает управление самому приложению Express; поэтому она помещается в app (по соглашению).

Следующая строка — то, что в Express называют маршрутом (route). Это во многих отношениях аналогично таблицам маршрутизации (routing tables), более популярным в ASP.NET и новых версиях ASP.NET MVC. Маршрут сопоставляет команду запроса (get) и относительный URL (в данном случае — «/») с какой-либо функцией. В моем примере это литерал анонимной функции, которая реагирует сообщением «Hello World». Заметьте, что функция также использует объект debug для вывода короткой строки после получения запроса.

Наконец, код проверяет текущую среду, чтобы выяснить, указана ли переменная окружения PORT (которая непременно будет в Azure). Если не указана, назначается порт 3000. Затем объекту app сообщается, чтобы он прослушивал этот порт; данный вызов является блокирующим. Он будет выполняться литералом анонимной функции, передаваемым при начале прослушивания. Далее процесс просто ожидает входящий запрос. Предполагая, что запрос будет адресован на «/», он отвечает сообщением «Hello World».

Debug, Express и вы

Как упоминалось в прошлой статье, отладочный вывод не появляется, пока переменной окружения DEBUG не присвоена та же строка, которая использовалась на этапе require. В данном случае это app. Express также использует debug, и, если DEBUG установлена в «*», будет отображаться и весь диагностический вывод Express. Это слишком объемно для использования в отладке на регулярной основе, но может оказаться полезным на ранних этапах работы с Express. Это поможет вам составить представление о различных частях и о том, что и когда вызывается. Пример такого вывода (с несколькими запросами) приведен на рис. 4.

Express с отладочным протоколированием
Рис. 4. Express с отладочным протоколированием

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

DEBUG=app,express:router,express:router:layer

Эта команда будет отображать вывод только от этих трех отладочных потоков.

Заключение

Во многих отношениях Express похож на ASP.NET. Он не только аналогично обрабатывает HTTP-трафик, но и служит своего рода центральный хабом, вокруг которого «располагаются» десятки (если не сотни) других зависимых и расширяющих пакетов. Например, пакет serve-static позволяет приложению Express обслуживать каталог статических ресурсов (т. е. ресурсов, не выполняемых на серверной стороне), таких как изображения и шрифты. В следующей статье я начну рассматривать, как использовать Express-объекты request и response. (Если вы не можете ждать, проверьте документацию Express на expressjs.com.) А тем временем,… удачи в кодировании!


Тэд Ньюард (Ted Neward) — директор iTrellis по технологиям (эта компания предоставляет консалтинговые услуги). Автор и соавтор многочисленных книг, в том числе «Professional F# 2.0» (Wrox, 2010), более сотни статей, часто выступает на многих конференциях по всему миру; кроме того, имеет звание Microsoft MVP в области F#. С ним можно связаться по адресу ted@tedneward.com или ted@itrellis.com.

Выражаю благодарность за рецензирование статьи эксперту Шону Уайлдермуту (Shawn Wildermuth).