20Sep

maxresdefault

Всем привет! На этом занятии мы познакомимся с Node.js уже в роли веб-сервера. Создадим для этого новое приложение. Настройте пожалуйста свой редактор таким образом чтобы он знал что  вы делаете именно Node.js-проект и поддерживал соответствующие автодополнения и глобальные переменные. Далее создадим server.js и в нем первым делом подключаю модуль:

var http = require('http');

Об этом модуле мы еще поговорим подробнее, но на текущий момент нам необходим из него один объект:

var server = new http.Server();

Как следует из его названия, он умеет слушать ip-порт и отвечать на входящие запросы. Для того, чтобы дать ему ip-порт, используется команда:

server.listen(1337, '127.0.0.1');

А для того, чтобы отвечать на запросы, используются события. Сервер является  EventEmitter, и при входящих запросах инициируется соответствующее событие, которое называется request. Его обработчик получает два объекта:

server.on('request', function(req, res) {  
  res.end("Hello, world!");  
});  

Первый requestэто входящий запрос, он содержит информацию, которая присылает браузер, включая, в частности, url пришедшего запроса. И второй параметр – это объект ответа. Из первого мы читаем, во второй пишем. Конкретно эта функция тут же заканчивает выполнение запроса, отсылая фразу «Hello, world!». Давайте посмотрим, как это работает. Для этого я создам конфигурацию у себя в WebSorm 2016 для запуска Node.js приложения. Выбираем Node.js, там уже указан путь к Node. Добавляем  путь к исполнимому файлу. Пожалуйста повторите эту процедуру но уже в своем редакторе. Запустим наш server. Работает.

Теперь зайдем на url браузера – http://127.0.0.1:1337/ . Замечательно! По виду все работает. Чтоб в этом убедиться, создадим  переменную

var counter = 0;

server.on('request', function(req, res) {
    res.end("Hello, world!"+ ++counter);
});

которая будет вводить текущий считчик запросов.  Захожу в браузер и попытаюсь обновить страницу. Но мои попытки не приносят результата. Почему? Node.js устроен так, что запустившись и считав файл модуля, в данном случае это главный файл, он же и единственный, Node создает из него объект module, и этим объектом в дальнейшее пользуется. Соответственно, при изменениях данного файла Node просто не подбирает эти изменения, потому что файл уже обработан, а объект module готов. Чтобы заставить Node перечитать файл, самый простой способ – запустить сервер еще раз. Но если я сейчас нажму play, то произойдет ошибка: EADDRINUSE – это означает, что адрес уже используется, потому что Node server.js попыталась запуститься еще раз, не прекратив действия уже запущенной программы. Предыдущий сервер уже занял этот ip-порт.  Что делать? Например, можно взять и подредактировать конфигурацию, добавив галочку в Single instance only (сервер может быть запущен в единственном экземпляре). Жмем повторный play, который нам предложить убить текущий запуск. Попрошу не предупреждать об этом в будущем, а просто убивать его. Теперь снова повторное нажатие кнопки play или Ctrl+R будут перезапускать текущий сервер, а вовсе не делать новый. Если вы работаете в console, то это вообще не проблема. Убиваете текущий Node.js, стартуете новый. В дальнейшем мы посмотрим, как это оптимизировать.

Теперь перехожу в браузер и нажимаю Ctrl+R. Как видим, счетчик запросов увеличивается не на 1, а на 2. Это потому что браузер устроен так, что вместе с собственной страничкой он делает еще один запрос. Он делается на url favicon.ico. В данном случае, мы никакой favicon.ico не отдаем, поэтому браузер каждый раз его повторяет. Получается, что одно обновление страницы приводит к двум запросам, по крайней мере, в текущем контексте, в Chrome.

Мы сделали наш первый сервер на Node.js. В дальнейшем будем работать, чтобы сделать его гораздо мощнее, интереснее. Перед тем, как мы продолжим, небольшая ремарка: если вы смотрите сам сайт Node.js, то пример, аналогичный нашему. там выглядит немножко по-другому. Основное отличие в том, что здесь используется new server, а там http createServer.  Это одно и то же. Здесь обработчик запроса ставится явно, а там он передается аргументам. Передача аргументов – это тоже установка обработчика, просто такой дополнительный синтаксис. Он чуть-чуть короче, но я выбрал для примера этот синтаксис, потому что он более нагляден и показывает то, что реально происходит.

А теперь, если вы внимательно слушали, то у вас не вызовет проблемы ответить на следующий небольшой вопрос. Здесь есть обработчик события request, скажите, пожалуйста, как, не глядя в документацию, сказать, какие еще есть события для сервера и когда они вызываются, в каком порядке при обработке этого запроса? Почему я прошу не смотреть в документацию? Тут две причины. Во-первых, так интереснее, во-вторых, сервер (var server = new http.Server()  ), на самом деле, наследует net.Server, модуля net, а он  наследует EventEmitter:

// http.Servernet.Server→EventEmitter

 

Вот такая иерархия. Соответственно, некоторые события сервера описаны вот здесь, в http.Server а  некоторые описаны в документации к net.Server:

И просто, взглянув в книгу, понять точный порядок событий достаточно сложно. Сейчас я расскажу, как это сделать. Подсказка находиться вот в этой строке:

// http.Servernet.Server→ EventEmitter

Сервер является EventEmitter. Это означает, что все события генерируются вызовом server.emit. понятно, что мы сами не вызываем этот метод, в данном случае его вызывает сам Node.js, а мы просто ставим обработчики. Но ничто нам не мешает переопределить этот метод на наш собственный. Метод emit принимает название события и необходимые данные для него:

var counter = 0;  
  
var emit = server.emit;  
server.emit = function(event/*, arg1, arg2,... */) {  
};  

В данном случае это будут req, res. Но нас интересуют только названия событий, которые мы при помощи console.log будем выводить.  А далее мы буде передавать вызов исходному методу emit:

var emit = server.emit;
server.emit = function(event/*, arg1, arg2,... */) {
    console.log(event);
    return emit.apply(this, arguments);
};
server.on('request', function(req, res) {
    res.end("Hello, world!"+ ++counter);
});

Посмотрим, что получилось. Перезапустим сервер. И тут же видим первое событие – listening. Это означает, что сервер начал слушать соединение:

server.listen(1337, '127.0.0.1');

Далее, захожу в браузер и перехожу по адресу. Обратите внимание, я нажимаю Ctrl+R, и request увеличивается, причем, даже по 2 штуки. А connection одно-другое, а новых нет, потому что это событие connection возникает тогда, когда браузер открывает серверу новое сетевое соединение, а request присылает запрос. Браузер устроен так, что одно сетевое соединение он старается использовать по максимуму. Называется это KeepAlive. Он его сохраняет и по нему гонит новые запросы.

Итак, мы создали простейший веб-сервер, познакомились с соответствующим объектом http.Server и событиями, которые в нем возникают.

Код нашего урока можно найти в нашем репозитории.

D-03-WebServeHosting

Материалы урока взяты из следующего скринкаста.

 We are looking forward to meeting you on our website soshace.com

3. Уроки Express.js. Шаблонизация с EJS: Layout, Block, Partials

В реальной жизни у нас обычно больше, чем один шаблон. Более того, если уж так получилось, что мы делаем сайт со страницами, то, как правило, бывает так, что у нас множество страниц есть в одинаковом оформлении. Шаблонная система должна это предусматривать. К сожалению, ejs не очень хорошо с этим справляется. Поэтому, мы сейчас поставим немного другую систему для шаблонизации , которая называется ejs-locals(добавим в app.js)

22. Чат Через Long-Polling. Чтение POST. Pt.2.

Соответственно, что бы мы не записали, отправляется одно и то же. Давайте мы это поправим. Сообщения у нас отправляются методом POST. Для того, чтобы считать этот метод из req, нужно поработать с ним, как с потоком. Для этого посмотрим на следующую схему, которая описывает жизненный цикл запроса, а именно объектов req и res.

Leave a Reply