Advertisement
  1. Code
  2. Express
Code

Построение готового MVC вебсайта с использованием ExpressJS

by
Difficulty:IntermediateLength:LongLanguages:

Russian (Pусский) translation by AlexBioJS (you can also view the original English article)

В этой статье мы будем разрабатывать готовый вебсайт как клиентскую часть, так и Панель Управления для работы с контентом Как вы уже, наверное, догадались, окончательная рабочая версия приложения содержит уйму различных файлов. Я старался пошагово писать данное руководство, включая процесс разработки, но все же я не включал каждый отдельный файл, т.к. это привело бы к тому, что руководство стало бы слишком длинным и неинтересным. Не смотря на это, все исходные файлы доступны на GitHub и я очень рекомендую на них взглянуть.


Введение

Express - это один из лучших фреймворков для Node. У него отличная тех. поддержка, а также он имеет кучу полезных особенностей.(фич?!) Существует множество отличных статей, в которых рассматриваются основы. Не смотря на это, я хотел бы пойти немного дальше и поделиться с вами моим способом создания вебсайта. В целом, эта статья не только об Express, а скорее о сочетании его с другими отличными инструментами, которые доступны для Node-разработчиков.

Я предполагаю, что вы знакомы с Nodejs, уже установили систему, и, возможно, уже имеете какой-то опыт в создании приложений.

В сердце Express лежит Connect Это промежуточный фреймворк, который содержит много полезных материалов. Если вы удивлены, почему он является промежуточным, вот вам небольшой пример:

В основном, промежуточной является функция, которая принимает request и response объекты, а также функцию next.  Каждый middleware решает отвечать, используя объект response  или передать следующей функции, вызвав next callback. В примере выше, если будет удален метод next() во втором middleware, строка hello world никогда не будет отправлена браузеру. В основном, это как раз то, как работает Express. Имеется некоторое встроенное промежуточное ПО, которое, конечно же, экономит вам множество времени (* в Express 4 все встроенное промежуточное ПО удалено, за исключением express.static). Например Bodyparser, при помощи которого разбираются тела запросов и который поддерживает следующие типы контента:  application/json, application/x-www-form-urlencoded и multipart/form-data. Или же Cookie parser, при помощи которого разбирается заголовок Cookie и устанавливается в качестве значения req.cookies объект, ключами которого являются названия куки.

Express, собственно, оборачивает Connect и добавляет к нему новые функциональные возможности. Как, например, логику маршрутизации, благодаря чему процесс обработки запросов намного упрощается. Ниже приведен пример обработки запроса по методу GET.


Установка

Имеется два способа установки Express. Первый реализуется за счет указания его в качестве зависимости в вашем файле package.json и выполнения команды npm install (есть шутка, что npm означает no problem man (* без проблем, чувак) :)):

Код фреймворка будет помещен в папку node_modules, и вы сможете создать его экземпляр. Однако я предпочитаю альтернативный вариант, при котором используется командная строка. Просто установите Express глобально (* благодаря чему модуль может быть использован в качестве инструмента командной строки независимо от того, в какой директории вы находитесь) при помощи выполнения команды npm install -g express. За счет этого теперь у вас имеется совершенно новый инструмент командной строки. Например, если вы выполните следующую команду:

то при помощи Express будет создан каркас приложения с уже настроенными для вас некоторыми моментами. Ниже приведены опции, которыми можно воспользоваться при выполнении команды express(1):

Как вы видите, доступно всего несколько опций, однако мне их достаточно. Обычно я использую less в качестве препроцессора CSS и hogan в качестве шаблонизатора (* программное обеспечение для комбинирования шаблонов с моделью данных для получения конечных документов). В нашем примере также будет необходима поддержка сессий, что решается за счет добавления аргумента --sessions. После завершения выполнения вышеуказанных команд наш проект выглядит следующим образом:

Если вы ознакомитесь с файлом package.json, то увидите, что все необходимые нам зависимости добавлены в него. Однако они еще не были установлены. Для этого просто выполните npm install, и после этого они будут добавлены в папку node_modules.

Я понимаю, что вышеуказанный способ не всегда подходит. Возможно, вы хотите поместить ваши обработчики маршрутов в другую папку или изменить что-либо еще. Но как вы увидите в следующих нескольких частях, я внесу изменения в уже сгенерированную структуру, что очень просто выполнить. Так что вы должны просто рассматривать команду express(1) как команду для создания шаблона.


FastDelivery

Для этого руководства я создал простой веб-сайт выдуманной компании под названием FastDelivery. Ниже приводится скриншот завершенного дизайна:

site

К концу этого руководства у нас будет готовое веб-приложение с рабочей панелью управления. Идея состоит в том, чтобы реализовать возможность управления каждой частью приложения в отдельных предназначенных только для определенного круга пользователей областях. Макет был создан в Photoshop и сверстан при помощи кода CSS(less) и HTML(hogan). Теперь вот что: я не буду рассматривать процесс верстки, поскольку это не касается обсуждаемой в данном руководстве темы, однако если у вас имеются какие-либо вопросы по этому поводу, то смело задавайте. После выполнения верстки у нас имеются следующие файлы и структура приложения:

Ниже перечислен список чатсей сайта, которыми мы будем управлять:

  • Home (* Домашняя страница) (баннер (заголовок) посередине и текст)
  • Blog (* Блог) (для добавления, удаления и редактирования статей)
  • Services page (* Услуги)
  • Careers page (* Вакансии)
  • Contacts page (* Контакты)

Настройка

Нам необходимо выполнить кое-что перед тем, как начать собственно реализацию приложения. К этому относится настройка конфигурации (* набор аппаратных и/или программных установок (например, положений переключателей, значений переменных, управляющих последовательностей), задающих состав системы или приложения, функциональные возможности и/или режимы функционирования устройства или программы) приложения. Давайте представим, что наше небольшое приложение должно быть доставлено в три различных места – локальный сервер, вспомогательный сервер (* служит для предварительного просмотра и проверки нового контента перед публикацией на рабочих серверах Сети) и сервер для размещения финальной версии приложения. Естественно, что настройки для каждой среды различаются и нам необходимо реализовать достаточно гибкий механизм для перехода между средами. Как вы знаете, каждый скрипт node выполняется в качестве консольного приложения. Поэтому мы можем с легкостью передать аргументы в командной строке, при помощи которых будет определяться текущая среда. Я оформил часть кода для настройки конфигурации в качестве отдельного модуля, чтобы написать тест для нее позже. Ниже приводится код содержащегося в папке /config/ файла index.js:

Пока в нем используются только две настройки: mode (* режим) и port (* порт). Как вы, возможно, догадываетесь, в приложении используются различные порты для различных серверов. Поэтому нам необходимо обновить точку входа (* адрес команды, с которой начинается выполнение какого-либо участка кода. Обычно говорят о точках входа в подпрограмму, функцию, драйвер или процедуру) приложения в app.js.

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

будет выведено сообщение

Теперь все наши настройки находятся в одном месте и ими легко управлять.


Тесты

Я большой фанат разработки через тестирование (* Test-driven development (TDD)). Я попробую рассмотреть все используемые в этом руководстве основные классы (* модули). Естественно, что в случае обсуждения тестов для всего кода это руководство было бы слишком длинным, однако в целом, именно так вам следует поступать при создании ваших собственных приложений. Один из моих любимых фреймворков для тестирования – jasmine. Конечно же, он доступен в реестре npm:

Давайте создадим папку tests, в которой будут содержаться наши тесты. Первое, что мы протестируем – настройка конфигурации. Файлы с техническими характеристиками (* документ, который в идеале содержит полное, точное, детальное описание функций и/или параметров (например, продукта, программы, стандарта и т. п.), а также, возможно, процедур, позволяющих определить, соответствует ли продукт данной спецификации.   документ, описывающий требования, которым должны соответствовать продукт или услуга) должны оканчиваться на .spec.js, так что файл должен называться config.spec.js.

Выполните команду jasmine-node ./tests, и вы должны будете увидеть следующее:

В этот раз я написал вначале реализацию и затем тест к ней. Это не совсем соответствует принципам разработки через тестирование, однако в следующих нескольких разделах я буду поступать наоборот.

Я очень вам рекомендую потратить значительное количество времени на написание тестов. Нет ничего лучше, чем полностью протестированное приложение.

Несколько лет назад я осознал кое-то важное, что может помочь вам разрабатывать более качественные программы. Каждый раз, когда начинаете писать новый класс, новый модуль или просто новый кусочек логики, спросите себя:

Как мне это протестировать?

Ответ на этот вопрос поможет вам повысить эффективность при написании кода, создавать лучшие API и оформлять весь код в виде аккуратно отделенных блоков. У вас не получится написать тесты для запутанного кода (* любая плохо спроектированная, слабо структурированная и трудная для понимания программа. В строгом смысле, любая программа, не следующая стандартам, правилам или методологии разработки). Например, в конфигурационном файле выше (/config/index.js) я добавил возможность передачи mode в конструктор модуля. Вы, возможно, не понимаете, зачем я это делаю, когда основная идея – получить значение mode из аргументов командной строки. Все просто... потому что мне необходимо было протестировать ту функциональную возможность. Давайте представим, что месяц спустя мне нужно проверить кое-что в конфигурации, предназначенной для финальной версии приложения (production), однако при этом запускать скрипт node с параметром staging. У меня бы не получилось это выполнить без того незначительного усовершенствования. Тот предыдущий небольшой шаг теперь по сути избавляет меня от проблем в будущем.


База данных

Поскольку мы создаем динамический веб-сайт, нам необходима база данных для хранения в ней наших данных. Я решил использовать mongodb для этого руководства. Mongo – документальная база данных (* упорядоченная совокупность взаимосвязанных документов; база данных, в которой каждая запись отражает конкретный документ, содержит его описание и, возможно, иную информацию о нем) NoSQL. Инструкции по установке могут быть найдены здесь, и поскольку я пользуюсь Windows, то я вместо этого последовал инструкциям для Windows. Сразу после окончания установки запустите демон (* процедура, запускаемая автоматически при выполнении некоторых условий; скрытая от пользователя служебная программа, вызываемая при выполнении какой-л. функции) MongoDB, который по умолчанию прослушивает подключения по 27017 порту. Что ж, теоретически у нас должна быть теперь возможность подключения к этому порту и обмена информацией с сервером mongodb. Для выполнения этого в скрипте node нам необходим модуль/драйвер mongodb. Если вы скачали исходные файлы для этого руководства, то модуль mongodb уже добавлен в файле package.json. Если же нет, то просто добавьте "mongodb": "1.3.10" в список ваших зависимостей и выполните npm install.

Далее мы напишем тест для проверки того, запущен ли сервер mongodb. Ниже приводится контент находящегося в папке /tests/ файла mongodb.spec.js:

Функция обратного вызова в методе .connect клиента mongodb получает объект db. Мы будем использовать его позже для управления нашими данными, и это означает, что нам необходим будет доступ к нему внутри наших моделей. Неразумно создавать новый объект MongoClient каждый раз, когда нам необходимо выполнить запрос к базе данных. Поэтому я переместил код для запуска сервера express в функцию обратного вызова функции connect:

Мы можем усовершенствовать код еще дальше. Поскольку у нас имеется настройка конфигурации, то было бы здорово поместить туда значения хоста и порта и затем изменить URL, используемый для подключения к базе данных, на:

Обратите особое внимание на промежуточное программное обеспечение attachDB, которое я добавил сразу перед вызовом функции http.createServer. Благодаря этому небольшому дополнению мы присвоим значение свойству .db объекта запроса. Хорошие новости заключаются в том, что мы можем подключить несколько функций при определении маршрута. Например:

Так что благодаря этому Express вызывает attachDB перед выполнением нашего обработчика маршрута. Сразу после этого объекту запроса будет добавлено свойство .db, и мы можем его использовать для доступа к базе данных.


MVC

Все мы знакомы с паттерном MVC (* Model-View-Controller – Модель-Представление-Контроллер; архитектурный паттерн программного обеспечения (паттерн разработки), обычно используемый для разработки пользовательских интерфейсов, согласно которому приложение разделяется на три взаимодействующие части). Вопрос заключается в том, как это относится к Express. В целом это зависит от интерпретации. В следующих нескольких разделах я создам модули, которые будут выполнять роль модели, представления и контроллера.

Модель

Модель – то, при помощи чего мы будем управлять имеющимися в нашем приложении данными. Она должна иметь доступ к объекту db, возвращенному MongoClient. У нашей модели также должен иметься метод для ее расширения, поскольку мы можем захотеть создать различные типы моделей. Например, мы бы могли захотеть создать BlogModel или  ContactsModel. Так что нам необходимо написать новые технические характеристики – /tests/base.model.spec.js для того, чтобы протестировать эти две возможности модели. И помните, что за счет определения этих функциональных возможностей до начала их реализации мы можем гарантировать, что наш модуль будет выполнять только то, что нам необходимо.

Вместо передачи настоящего объекта db я решил передать его имитацию. Я это сделал, поскольку позднее мне может потребоваться протестировать что-то определенное, зависящее от поступающей из базы данных информации. Будет намного проще определить эти данные вручную.

Мы просто запросим модуль вверху нашего файла. К счастью, у нас уже написан замечательный тест, при помощи которого подтверждается, что наш код работает. Версия модуля, которая проходит вышеуказанный тест, выглядит следующим образом:

Здесь у нас имеется два вспомогательных метода. Сеттер для объекта db и геттер для нашей коллекции базы данных.

Представление

Представление отобразит информацию на экран. По сути, представление – класс, который отправляет ответ браузеру. Express предоставляет легкий способ для выполнения этого:

Объект ответа – обертка с замечательным API, что облегчает нам жизнь. Однако я бы предпочел создать модуль, который инкапсулировал бы этот функционал. Мы заменим заданную по умолчанию папку для представлений views на templates и создадим новое представление, в котором будет располагаться класс представления Base. Для выполнения этого небольшого изменения нужно внести еще одно. Нам необходимо указать Express, что наши файлы шаблонов теперь располагаются в другой папке:

Для начала я опишу то, что мне нужно, напишу тест и после этого напишу код для реализации обсуждаемого здесь функционала. Нам необходим модуль, который удовлетворяет следующим требованиям:

  • Его конструктор должен получать объект ответа и имя шаблона.
  • Он должен иметь метод render, который принимает объект с данными.
  • У него должна иметься возможность расширения.

Вам, возможно, не совсем понятно, зачем я расширяю класс View. Разве он не служит просто для вызова метода response.render? Что ж, на практике имеются классы, в которых вы захотите отправить другой заголовок или, возможно, изменить объект response каким-то образом. Как, например, при отправлении данных в формате JSON:

Вместо того чтобы выполнять это каждый раз, было бы замечательно, если бы у нас имелись классы JSONView и HTMLView. Или даже класс XMLView для отправления браузеру данных в формате XML. Просто лучше, если вы создаете крупный веб-сайт, обернуть такие функциональные возможности, а не копировать и вставлять тот же самый код снова и снова.

Ниже представлено описание требований, предъявляемых к  расположенному в папке /views/ Base.js:

Для того чтобы протестировать работу представления, я должен был создать имитацию объекта. В этом случае я создал объект, который имитирует объект ответа Express. Во второй части теста я создал другой класс View, который наследует функционал от базового и использует свой собственный метод render. Ниже приводится код для класса, описываемого в файле Base.js, расположенном в папке /views/:

Теперь у нас имеется три технические характеристики в нашей папке tests, и если вы выполните команду jasmine-node ./tests, то в результате в консоль будет выведено следующее:

Контроллер

Помните маршруты и как они были определены?

То, что идет после '/' в вышеуказанном примере маршрута, является собственно контроллером. Это просто функция промежуточного программного обеспечения, которая принимает request, response и next.

Выше показано, как должен выглядеть ваш контроллер в контексте Express. Инструмент командной строки express(1) создает папку под названием routes, однако в нашем случае более удачное имя – controllers, так что я изменил ее название, чтобы оно соответствовало требованиям необходимой нам схемы наименования.

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

  • класс должен иметь метод extend, который принимает объект и возвращает новый дочерний образец;
  • дочерний образец должен иметь метод run – старую функцию промежуточного программного обеспечения;
  • класс должен иметь свойство name, которое служит для идентификации контроллера;
  • у нас должна иметься возможность создания независимых объектов на основе этого класса;

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

А ниже приводится реализация расположенного в папке /controllers/ Base.js:

Естественно, что в каждом дочернем классе должен определяться свой собственный метод run с его собственной логикой.


Веб-сайт FastDelivery

Что ж, у нас имеется хороший набор классов для нашей архитектуры, удовлетворяющей требованиям MVC, и мы рассмотрели наши недавно созданные модули с тестами. Теперь мы готовы продолжить разработку сайта нашей выдуманной компании FastDelivery. Давайте представим, что у сайта имеется две части: клиентская часть и административная панель. Клиентская часть будет использоваться для отображения записанной в базе данных информации нашим конечным пользователям. Административная панель будет использоваться для управления теми данными. Давайте для начала разберемся с нашей административной панелью (панелью управления).

Панель управления

Давайте для начала создадим простой контроллер, который будет использоваться для создания страницы для администратора. Содержимое файла Admin.js, расположенного в папке /controllers/, приводится ниже:

За счет использования заранее написанных базовых классов для наших контроллеров и представлений мы можем с легкостью создать точку входа (* адрес команды, с которой начинается выполнение какого-либо участка кода. Обычно говорят о точках входа в подпрограмму, функцию, драйвер или процедуру) для панели управления. Класс View принимает имя файла шаблона. Согласно коду выше файл должен называться admin.hjs и должен размещаться в папке /templates. Контент шаблона выглядел бы примерно так:

(Для того чтобы это руководство оставалось относительно коротким и в удобном для прочтения формате, я не буду здесь рассматривать все шаблоны представлений. Я вам очень рекомендую скачать исходный код с GitHub)

Теперь для применения рассмотренного выше контроллера нам необходимо добавить для него маршрут в app.js:

Обратите внимание, что мы не пересылаем метод Admin.run непосредственно в качестве промежуточного ПО. Это так, поскольку мы хотим сохранить верный контекст. Если мы сделаем следующее

то ключевое слово this в Admin будет указывать на какой-то иной контекст.

Защищаем панель администратора

Каждая страница, путь которой начинается с /admin, должна быть защищена. Для этого мы будем использовать промежуточное ПО Express для реализации сессий. При помощи него просто присоединяется объект к объекту запроса под названием session. Теперь нам необходимо изменить наш контроллер Admin для выполнения двух дополнительных заданий:

  • он должен проверить наличие свойства session; при его отсутствии должна быть передана форма для регистрации;
  • он должен принять отправленные в форме данные и авторизовать пользователя при совпадении имени пользователя и пароля;

Ниже приводится небольшая вспомогательная функция, которую мы можем использовать для выполнения вышеуказанных требований:

Вначале у нас имеется предложение, при помощи которого выполняется попытка распознавания пользователя с использованием объекта session. Затем мы проверяем, была ли прислана форма. Если да, то данные формы становятся доступны в объекте request.body, значение которого устанавливается при помощи промежуточного ПО bodyParser. Затем проверяем, совпадали ли имя пользователя и пароль.

А теперь переходим к методу run контроллера, в котором используется наш новый вспомогательный метод. Мы проверяем, авторизован ли пользователь, и в зависимости от результата отображаем либо саму панель управления, либо страницу для входа в систему.

Управление контентом

Как упомянул в начале руководства, нам необходимо управлять многими частями веб-сайта. Для облегчения процесса давайте хранить все данные в одной коллекции. У каждой записи будут свойства title, text, picture и type. При помощи свойства type будет определяться, к какой части приложения принадлежит запись. Например, для страницы Contacts будет необходима только одна запись с type: 'contacts', тогда как для страницы Blog будет необходимо множество записей. Что ж, нам необходимы три страницы для добавления, редактирования и отображения записей. Перед тем как мы приступим к созданию новых шаблонов, добавлению стилевого оформления и новых возможностей для контроллера, нам необходимо написать наш класс для модели, которая находится между сервером MongoDB и нашим приложением и, естественно, предоставляет понятный API.

При помощи этой модели для каждой записи генерируется уникальный ID. Он нам пригодится для обновления информации в дальнейшем.

Если нам нужно добавить новую запись для нашей страницы Contacts, то мы можем просто воспользоваться следующим кодом:

Что ж, у нас имеется API для управления данными нашей коллекции mongodb. Теперь мы готовы к написанию кода для UI (* интерфейс пользователя), чтобы воспользоваться этим функционалом. Переходим к первой части приложения. Контроллер Admin необходимо будет изменить довольно существенно. Для упрощения нашей задачи я решил скомбинировать список добавленных записей и форму для их добавления/редактирования. Как вы видите на скриншоте ниже, левая часть страницы отведена для списка, а правая часть – для формы.

control-panel

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

Этот код выглядит немного страшновато, но работает как нам это необходимо. Первый вспомогательный метод – метод del, при помощи которого проверяются текущие параметры запроса по методу GET, и если он обнаруживает action=delete&id=[id of the record], то удаляет данные из коллекции. Вторая функция называется form и отвечает, главным образом, за отображение формы справа страницы. При помощи нее проверяется, отправлена ли форма, и должным образом обновляются или создаются записи в базе данных. В конце кода метод list получает информацию и подготавливает HTML-таблицу, которая позже отправляется щаблону. С реализацией этих трех вспомогательных функций вы можете ознакомиться в исходном коде для этого руководства.

Далее я решил показать вам функцию, при помощи которой обеспечивается закачивание файлов:

Если файл был отправлен, то свойство .files объекта запроса скрипта node заполняется данными. В нашем случае у нас имеется следующий элемент HTML:

Это означает, что мы могли бы получить доступ к присланным данным при помощи req.files.picture. В вышеуказанном фрагменте кода req.files.picture.path используется для получения первичных данных файла. Позже те же данные записываются в недавно созданную папку, и в конце кода возвращается соответственный URL. Все эти операции выполняются синхронно, однако согласно устоявшейся практике следует использовать асинхронный вариант методов readFileSync, mkdirSync и writeFileSync.

Клиентская часть приложения

С самым сложным мы теперь разобрались. Административная панель работает, и у нас имеется класс ContentModel, который предоставляет нам доступ к хранящейся в базе данных информации. Теперь нам необходимо написать контроллеры для клиентской части и привязать их к хранящимся данным.

Ниже приводится код контроллера для страницы Home, расположенный в файле Home.js (папка /controllers/):

Для Домашней страницы необходима одна запись типа home и четыре записи типа blog. После реализации контроллера нам всего лишь необходимо добавить маршрут для него в app.js:

Опять-таки, мы добавляем объект db к объекту запроса. Работаем с этим контроллером подобно тому, как работали с административной панелью.

Остальные страницы для нашей клиентской части очень подобны рассмотренной выше тем, что для них всех имеется контроллер, за счет которого извлекаются необходимые данные при помощи класса модели, и, конечно же, создается определенный маршрут. При этом имеется две интересные ситуации, которые мне хотелось бы обсудить более подробно. Первая связана со страницей для блога. Для этой страницы должна иметься возможность как отображения всех статей, так и только одной. Так что нам необходимо зарегистрировать два маршрута:

В них обоих используется один и тот же контроллер – Blog, однако вызываются различные методы run. Обратите внимание на строку /blog/:id. Этот маршрут будет обрабатывать запросы, выполняемые по адресам вроде /blog/4e3455635b4a6f6dccfaa1e50ee71f1cde75222b, и длинный фрагмент будет доступен в req.params.id. Другими словами, у нас имеется возможность определения динамических параметров. В нашем случае это ID записи. После получения этой информации мы можем создать уникальную страницу для каждой статьи.

Второй интересный момент заключается в том, как я создал страницы Services, Careers и Contacts. Понятно, что они используют только одну запись из базы данных. Если бы нам необходимо было создать отдельный контроллер для каждой страницы, то мы должны были бы копировать/вставлять тот же самый код и просто менять значение поля type. Имеется, однако, более удачный способ достижения этого с использованием только одного контроллера, который принимает определенное значение type и соответствующий ему метод run. Что ж, ниже приведен код для маршрутов:

А контроллер выглядел бы примерно следующим образом:


Развертываем приложение на сервере

Развертывание приложения, созданного на основе Express, собственно, ничем не отличается от развертывания любого другого приложения Node.js.

  • Файлы закачиваются на сервер.
  • Процесс (* набор из одного и более тредов (потоков) и ассоциированных с ними системных ресурсов. Важное свойство процесса - он исполняется в своём собственном изолированном адресном пространстве и состоит как минимум из одного треда) node должен быть остановлен (если он запущен).
  • Должна быть выполнена команда npm install для установки новых зависимостей (если таковые имеются).
  • Основной скрипт должен быть затем снова запущен.

Имейте ввиду, что Node – по-прежнему довольно молодая платформа, так что не все может работать как положено, однако она постоянно совершенствуется. Например, при помощи forever гарантируется, что ваша программа Node будет выполняться постоянно. Вы можете это выполнить за счет выдачи следующей команды:

Я также пользуюсь этим инструментом на моем сервере. Это замечательный небольшой инструмент, который однако решает значительную проблему. Если вы запускаете ваше приложение просто за счет команды node yourapp.js, то после неожиданного завершения работы сервер прекращает работать. forever просто перезапускает приложение.

Теперь вот что, я не являюсь администратором, однако я хотел бы поделиться моим опытом интегрирования приложений Node с серверам Apache или Nginx, поскольку я считаю, что  так или иначе это относится к процессу разработки.

Как вы знаете, Apache обычно прослушивает подключения по 80 порту, и это означает, что если вы перейдете по адресу http://localhost или http://localhost:80, то увидите страницу, отправленную сервером Apache, и, скорее всего, скрипт вашего приложения node прослушивает подключения по иному порту. Так что вам необходимо добавить виртуальный хост, который принимает запросы и отправляет их на необходимый порт. Например, давайте предположим, что я хочу разместить только что созданный мною сайт на моем локальном сервере Apache, доступ к которому осуществляется по адресу expresscompletewebsite.dev. Для начала нам необходимо добавить наш домен в файл hosts.

Далее мы должны открыть файл httpd-vhosts.conf в папке, используемой для конфигурации Apache, и добавить туда следующий код:

После этого сервер по-прежнему прослушивает запросы по 80 порту, однако будет пересылает их на 3000 порт, который прослушивает приложение Node.

Устанавливать на Nginx намного проще, и, честно говоря, это более удачный выбор для размещения приложений, разработанных при помощи платформы Node.js. Вам по-прежнему необходимо добавить имя домена в вашем файле hosts. После этого просто создайте новый файл в папке /sites-enabled, располагающейся в папке, где установлен Nginx. Контент файла выглядел бы примерно следующим образом:

Учтите, что вы не можете запустить ни Apache, ни Nginx, используя вышеуказанные настройки хоста. Это так, поскольку для работы этих обоих серверов необходим порт 80.  Также вам могут потребоваться дополнительные сведения для более удачной настройки конфигурации сервера, если вы планируете использовать обсуждаемые выше фрагменты кода в среде для выполнения конечной версии приложения. Как я сказал ранее, я не являюсь экспертом в этой области.


Заключение

Express – замечательный фреймворк, который предоставляет вам хорошую отправную точку для начала создания приложений. Как вы понимаете, то, как вы его расширите и что будет использовать при работе с ним, зависит от вас. При помощи него упрощается выполнение рутинных задач за счет использования некоторого промежуточного ПО, а интересная часть работы остается разработчику.

Исходный код

Исходный код для примера созданного нами в этом руководстве сайта доступен на GitHub - https://github.com/tutsplus/build-complete-website-expressjs. При желании можете форкнуть его и поэкспериментировать с ним. Ниже перечислены шаги для запуска сайта:

  • Скачайте исходный код
  • Перейти в папку app
  • Выполните команду npm install
  • Выполните команду mongodb daemon
  • Выполните команду node app.js
Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.