- PVSM.RU - https://www.pvsm.ru -
Это не первая вводная статья про Impress [1] на Хабре, но за последний год я получил много вопросов и приобрел некоторый опыт в объяснении архитектуры и философии этого сервера приложений и, надеюсь, стал лучше понимать проблемы и задачи разработчиков, начинающих его освоение. Да и в самом сервере произошло достаточно [2] изменений, чтобы назрела актуальность совершенно новой вводной статьи.
Impress Application Server [3] (IAS) — это сервер приложений для Node.js [4] с альтернативной архитектурой и философией, не похожий на мэйнстрим разработки под нодой и призванный упростить и автоматизировать широкий круг повторяемых типовых задач, поднять уровень абстракции прикладного кода, задать рамки и структуру приложений, оптимизировать как производительность кода, так и производительность разработчиков. IAS покрывает сейчас только серверные задачи, но делает это комплексно, например, можно объединить на одном порту API, веб-сокеты, стриминг, статику, Server-Sent Events, проксирование и URL-реврайтинг, обслуживать несколько доменов и несколько приложений, как на одном сервере, так и на группе серверов, работающих в связке, как одно целое, как один сервер приложений.
Для начала, я хочу перечислить ряд проблем в общепринятом подходе для node.js, которые побудили меня начать разработку сервера приложений:
Есть еще много мелких проблем, а глубокое горе с отловом ошибок в Node.js, это тема для трех томов, залитых слезами, кровью и кофе (чаем). Как следствие всего перечисленного — нода, все еще вызывает опасения и, в большинстве случаев, используется как дополнительный инструмент в связке с другими серверными технологиями, выполняя подсобные работы, как то: скриптование сборки клиентских приложений, прототипирование или обеспечение доставки уведомлений по веб-сокетам. Очень редко можно встретить крупный проект, имеющий серверную часть исключительно на ноде.
Кроме негативной мотивации (перечисленные проблемы), были еще позитивные побуждающие факторы для разработки IAS (идеи и задачи):
IAS рассчитан для создания нескольких типов приложений:
Поддерживаются несколько способов создания API
Аналогом middleware для IAS является handler (обработчик) — это асинхронная функция, которая имеет два параметра (client и callback) и находится в отдельном файле (из которого и экспортируется). Когда вызывается callback, то сервер приложений IAS узнает, что обработка завершилась. Если функция не вызывает callback дольше таймаута, то IAS возвращает HTTP статус 408 (Request timeout) и фиксирует проблему в логах. Если при вызове обработчика происходит исключение, то IAS берет на себя ответ клиенту, отлов ошибки и восстановление работы оптимальным способом, вплоть до удаления и повторного создания песочницы с испорченными или утекшими структурами данных.
Пример API обработчика:
module.exports = function(client, callback) {
dbAlias.equipment.find({ type: client.fields.type }).toArray(function(err, nodes) {
if (!err) callback(nodes);
else callback({ message: 'Equipment of given type not found' }, 404);
});
}
Каждый HTTP запрос может вызвать исполнение нескольких обработчиков. Например, если запрошен URL http://domain.com/api/examle/method.json, а IAS установлен в /impress, то исполнение начнется с каталога /impress/appplications/domain.com/app/api/example/method.json/ и проходит следующие этапы:
Если в запрашиваемом каталоге нет нужного обработчика, то IAS будет искать его на один каталог выше, пока не дойдет до /app. Если обработчик есть в папке, то он может программно вызвать обработчик из каталога выше (или ближайший вверх по дереву) через client.inherited(). Таким образом, можно использовать дерево каталогов для формирования наследования и переопределения обработчиков. Например, вы можете формировать данные ответа в обработчике /api/example/request.js, а выдавать их в трех форматах: /api/example/method.json, /api/example/method.html (содержит еще и шаблоны для вывода в html), /api/example/method.csv (может содержать дополнительные действия, например, формирования заголовка таблицы). Или сделать общий обработчик ошибок для всего API в файле /api/error.js. Такой подход дает большую гибкость и позволяет сократить размеры кода, однако, мы платим за это известными ограничениями.
Расширения у каталогов означают автоматическую отдачу из них контента определенного типа, а значит, установку определенных HTTP заголовков и преобразование результата в нужный формат данных. Все это можно переопределить вручную, но использование расширений сокращает количество кода. Из коробки поддерживаются такие расширения: .json, .jsonp, .xml, .ajax, .csv, .ws, .sse и этот список просто расширяем при помощи плагинов.
Внутри обработчика видны следующие имена, через которые мы можем обращаться к функциям IAS и подключенным библиотекам:
client.req и client.res, API по работе с запросом, ссылки на сессию и авторизованного пользователя;api.fs.readFile(...) или api.async.parallel(...);require, console, Buffer, process, setTimeout, clearTimeout, setInterval, clearInterval, setImmediate, clearImmediate. Но мы можем в конфигурации запретить использование некоторых из них, например, отключив приложению require, и предоставив ему только определенный набор библиотек, автоматически загруженных в его неймспейс api.
Делать require в обработчиках не нужно, достаточно установить библиотеки в папку /impress через npm install и подключить их через конфигурацию /сonfig/sandbox.js (сначала в конфиге IAS, а потом локально в конфиге приложения). Далее библиотеки видны в обработчиках через api.libName, точно так же становятся видны и встроенные библиотеки, например, api.path.extname(...) и т.д.
Все базы данных и драйверы СУБД видны через db.name. Соединения настраиваются в /config/databases.js (для каждого приложения отдельно), устанавливаются при старте и автоматически восстанавливаются при потере связи. В комплекте идут драйверы для MongoDB, PostgreSQL и MySQL, обернутые в плагины для IAS, при желании за 30 минут можно обернуть в плагины драйвера любой СУБД.
Для типа контента html используется простой встроенный шаблонизатор, он нужен скорее не для полной генерации страниц на стороне сервера, а для сборки layout (основной разметки и расположения кусков интерфейса), а так же, для подстановки немногочисленных значений из структур данных в html. Шаблонизатор содержит инклады и итераторы, но более сложную шаблонизации нужно реализовывать уже в браузере при помощи React, Angular, EJS и т.д., запрашивая шаблоны и данные отдельно и собирая их в браузере (с переиспользованием шаблонов), что типично для динамических веб-приложений. Встроенный же шаблонизатор, начинает рендеринг с файла html.template и подставляет в него данные из client.context.data. Конструкция @fieldName@ подставит значение из поля, конструкция @[file]@ вставит файл file.template, а конструкция @[name]@ ... @[/name]@ реализует итератор по хешу или массиву с именем name.
Для обработчиков, возвращающих сериализованные данные (.json, .jsonp, .csv и т.д.) шаблонизация не нужна. Для них структура данных client.context.data просто сериализуется в JSON (с отсеканием рекурсии). Для удобства можно возвращать структуру данных из обработчика первым параметром callback({ field: "value" }); Если один обработчик вернул в callback данные или присвоил их в client.context.data, то следующие за ним (до конца жизни текущего HTTP запроса) могут читать и изменять данные.
Обработчики могут изменять http код статуса, добавлять свои http заголовки, но в штатном режиме они работают только с объектом client, у которого есть методы безопасного API: client.error(code), client.download(filePath, attachmentName, callback), client.cache(timeout), client.end(output) и т.д. Начиная с версии 0.1.157 в IAS реализована частичная поддержка обработчиков middleware, имеющих 3 параметра: req, res и next. Но нужно это крайне редко, а код, портированный из проектов на express или connect, обычно можно переписать в несколько раз короче и проще.
Создавать обработчики обоих типов, т.е. handler (с 2я параметрами) и middleware (с 3я параметрами) можно не только из файлов, а добавляя роутинг вручную, через вызовы методов, например:
application.get('/helloWorld.ajax', function(req, res, next) {
res.write('<h1>Middleware handler style</h1>');
next();
});
Серверный код не ограничивается обработчиками, приложение так же может содержать модель предметной области, специализированные библиотеки и утилиты, используемые во многих обработчиках, и другие «места», для размещения логики и данных. Все приложения, запускаемые в IAS размещаются в каталоге /applications и имеют следующую структуру:
http://hostname/,В ближайших версиях появятся еще такие каталоги (issue #195 [5]):
/static, а в качестве сборщика можно будет использовать несколько наиболее распространенных средств.Пусть эта статья останется вводной, так что, я не буду сейчас подробно описывать весь арсенал IAS и перегружать читателя. Ограничусь простым перечислением основного: регистрация сервисом (демоном), прозрачное масштабирование на много процессов и много серверов, встроенная система пользователей и сессий (в т.ч. анонимных и аутентифицированных), поддержка SSE (Server-Sent Events) и веб-сокетов с системой каналов и подписки на сообщения, поддержка проксирования запросов, URL-реврайтинг, интроспекция сетевого API и выдача индексов каталогов, управление доступом к каталогам через access.js (аналог .htaccess), конфигурирование приложений, логирование, прокручивание логов, отдача статики с кешированием в память, gzip компессия, поддержка HTTP заголовков «if-modified-since» и HTTP 304 (Not Modified), поддержка HTTPS, стриминг файлов с поддержкой отдачи по частям (с указанного места и до указанного места, что обычно используют плееры, например HTML5 video-тег через HTTP заголовки Content-Range и Accept-Ranges), есть скрипты быстрого развертывания сервера для чистых машин (CentOS, Ubuntu, Debian), встроенные механизмы межпроцессового взаимодействия через IPC, HTTP и ZeroMQ, специальное API для синхронизации состояния между процессами, встроенный механизм мониторинга здоровья серверов, подсистема запуска отложенных задач, возможность порождать воркеры (параллельные процессы), валидация структур данных и схем БД, генерация структур данных из схем для SQL-совместимых СУБД, автоматическая обработка ошибок и длинного стека, оптимизация сбора мусора, экранирование песочниц (sandboxes), поддержка HTTP basic authentication, обработка виртуальных хостов и виртуальных путей, приклеивание IP (sticky), плагины (в т.ч. passport, geoip, nodemailer, минификации js, трансляции sass и т.д.), подсистема юнит-тестирования, утилиты для upload/download файлов и многое другое.
Impress (IAS) активно развивается, каждую неделю появляется от 4 до 7 минорных версий. Сейчас актуальна версия 0.1.195 и на подходе версия 0.2, в которой мы зафиксируем структуру приложений и базовое API, соблюдая обратную совместимость для всех 0.2.x версий. В 0.2.x мы будем заниматься только вопросами оптимизации и исправлением ошибок, а расширение функциональности будет возможно только если это не потребует редизайна приложений, основанных на 0.2.x. Все крупные нововведения и эксперименты будут параллельно вводиться в ветке 0.3.x. Приглашаю всех желающих развивать проект, а со своей стороны обещаю поддерживать код, как минимум, до тех пор, пока это актуально. Версия же 1.0 появится только тогда, когда я пойму, что независимые разработчики полностью в состоянии поддерживать код. Сейчас готовится документация, которая до этого была невозможна из-за того, что структура и архитектура часто менялась, я опубликую ссылку на нее по готовности версии 0.2. До этого подробнее ознакомиться с IAS можно по примерам, которые устанавливаются вместе с IAS, как приложение по умолчанию.
Немного цифр по состоянию на 2015-01-11: загрузок из npm вчера: 1 338, за эту неделю: 5 997, за последний месяц: 21 223, звезд на github: 168, вклад в репозиторий: 8 человек, строк кода: 6 120, размер исходников: 207 Кб (из них ядро: 118Кб), усредненная цикломатическая сложность кода: 20, кол-во закрытых issues в github: 151, открытых issues: 9, дата первой опубликованной версии: 2013-06-08, кол-во сборок в Travis CI: 233, кол-во коммитов github: 468.
NPM: www.npmjs.com/package/impress [1]
Github: github.com/tshemsedinov/impress [3]
Автор: MarcusAurelius
Источник [6]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/javascript/79208
Ссылки в тексте:
[1] Impress: https://www.npmjs.com/package/impress
[2] достаточно: https://github.com/tshemsedinov/impress/graphs/contributors
[3] Impress Application Server: https://github.com/tshemsedinov/impress
[4] Node.js: http://nodejs.org/
[5] issue #195: https://github.com/tshemsedinov/impress/issues/195
[6] Источник: http://habrahabr.ru/post/247543/
Нажмите здесь для печати.