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

Уроки React. Урок 11. Pt.1.

На предыдущем уроке мы научились более удобным способом писать reducers используя удобные API для добавления/удаления элементов, не беспокоясь о том, что мы что-то изменим по дороге.

Теперь если мы с Вами посмотрим на наше приложение и откроем какую-нибудь статью, то увидим в console warnning. Наши propTypes предупреждают нас о наличии проблемы, еще до того момента как мы до нее доберемся. Это огромный плюс – то что мы их написали. О чем говорит этот warnning ?

Leave a Reply