Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

Реализация сервера JS: HTTP Server

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

Операционная система (ОС)

Основой основ для программиста можно считать ОС. Да, у нас есть ещё железо и архитектуру ЭВМ никто не отменял, но прикладному разработчику достаточно иметь общее понимание того, как работает железо, а вот от ОС не уйти совсем.

Процесс

Базовой единицей исполнения в ОС является процесс. Каждый раз, когда вы запускаете какую-либо программу, то запускается минимум один процесс. Кстати, может быть и больше, отсюда следует что программа != процесс. Список запущенных процессов можно посмотреть так:

$ ps -xf

PID TTY      STAT   TIME COMMAND
29 pts/1    S      0:00 bash
30 pts/1    S+     0:00  \_ top
22 pts/0    S      0:00 bash
32 pts/0    R+     0:00  \_ ps xf

Каждая строчка на рисунке выше – это информация о каком-либо процессе. Как видно, ОС содержит в себе различную информацию о каждом из процессов. На текущий момент нас интересует только один параметр, который называется PID. PID, как ни странно, расшифровывается как process identifier и фактически представляет из себя целое число, однозначно определяющее то, о каком процессе идет речь.

Сети

Основным (высокоуровневым) способом коммуникации между машинами является семейство протоколов TCP/IP. Большинство людей, которые пользуются интернетом или сетями в целом так или иначе слышали выражение ip адрес. Этот адрес (для версии IPv4) может выглядеть так: 10.0.152.23. Он указывает на какое-то устройство в сети, которое не обязательно представлено компьютером в привычном понимании этого слова.

Интерфейсы

По правде говоря, этот адрес связан даже не с самим устройством, а с конкретным интерфейсом устройства. Например, каждая сетевая карта будет представлена в системе как отдельный интерфейс. Кроме того, интерфейсы бывают виртуальными, то есть у них отсутствует физический элемент. Зачем это нужно? Самый тривиальный пример это так называемая обратная петля (loopback). Интерфейс, который присутствует по умолчанию в большинстве ОС. Любой трафик, посланный в этот интерфейс, тут же принимается им же.

Этот интерфейс позволяет обращаться к серверному приложению, расположенному на той же машине, без активного подключения к сети. Такая возможность особенно полезна для тестирования служб и их разработки. Адрес этого интерфейса всегда 127.0.0.1. Так же к нему можно обращаться по имени localhost.

Domain Name System

DNS - система доменных имён, благодаря которой нам необходимо запоминать только буквенные имена сайтов без необходимости знать конкретный ip адрес машины, на которую надо пойти. Общий принцип работы довольно прост. Каждый раз, когда в браузер вводится имя сайта, он обращается к специальным серверам и спрашивает их: 'Какой ip адрес у hexlet.io?'. Дальше происходит немного магии, и, в конце концов, эта система возвращает (если найдёт) этот адрес. Затем браузер устанавливает tcp соединение и начинает свою работу.

Порты

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

В tcp существует такое понятие, как порт. Это целое число, означающее точку входа в процесс запущенной программы. То есть при получении данных по tcp ОС смотрит то, для какого порта они предназначены. Затем она находит процесс, соответствующий этому порту, и передает данные в него. Важным следствием этого подхода становится тот факт, что невозможно занять уже занятый порт. Иначе это ввело бы неоднозначность. И действительно, при старте сервера, который пытается слушать занятый другой программой порт, будет получена такая ошибка:

Error: listen EADDRINUSE :::4000

Мы можем даже посмотреть на того, кто занял этот порт:

$ lsof -i :4000

COMMAND   PID     USER TYPE NODE NAME
node    40726 mokevnin IPv6 TCP  *:terabase (LISTEN)

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

Если вернуться к браузеру, то может возникнуть вопрос: почему мы не указываем порт, когда загружаем сайты, откуда браузер знает, куда стучаться на сервер? Ответ на этот вопрос крайне прост: браузер действительно знает порт, на который нужно идти. И по умолчанию это порт с номером 80.

Веб-сервер

Начнём с иллюстрации:

// server.js
import http from 'http';

const server = http.createServer((request, response) => {
  // content-length формируется автоматически!
  response.write('hello, world!');
  response.end();
});

const port = 4000;
server.listen(port, () => {
  console.log('Server has been started');
});
  1. Импортируется модуль http. Он встроен в nodejs и позволяет создать веб-сервер (и не только).
  2. Создаётся веб-сервер. В функцию createServer передается обработчик запросов. Он будет вызываться на каждый входящий запрос.
  3. Сервер вешается на порт.

Обработки запроса в данном примере как таковой нет. Сервер будет отвечать по http фразой hello, world! на любой входящий запрос. Делается это с помощью объекта response, который представляет собой http-ответ. В примере выше мы используем две функции интерфейса response. Функцию write, которая позволяет передать текст в теле http ответа, и функцию end, которая означает, что мы закончили формирование ответа. Обратите внимание: нам не пришлось руками выставлять заголовок content-length, модуль http самостоятельно вычисляет размер тела и подставляет необходимый заголовок.

Для запуска нашего сервера необходимо набрать команду:

$ node server.js # blocking

Запуск приводит к блокировке. Сервер запущен и работает. Чтобы его остановить, надо нажать комбинацию ctrl+c.

Теперь можно выполнить запрос к серверу:

Проделав данную процедуру, можно будет сказать, что вы запустили свой первый сайт на nodejs ;)

Но дальше нас поджидает сюрприз. Если попробовать поменять код сервера, и писать в ответ my first web server, то без перезапуска сервера ничего не изменится. После того, как сервер запущен, он больше не перечитывает файлы с диска и не изменяет своего состояния. Такое поведение не является особенностью модуля http, так устроен сам язык. Поэтому не забывайте перезапускать сервер, после внесения изменений.


Дополнительные материалы

  1. Что такое DNS

Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты.

Ошибки, сложный материал, вопросы >
Нашли опечатку или неточность?

Выделите текст, нажмите ctrl + enter и отправьте его нам. В течение нескольких дней мы исправим ошибку или улучшим формулировку.

Что-то не получается или материал кажется сложным?

Загляните в раздел «Обсуждение»:

  • задайте вопрос. Вы быстрее справитесь с трудностями и прокачаете навык постановки правильных вопросов, что пригодится и в учёбе, и в работе программистом;
  • расскажите о своих впечатлениях. Если курс слишком сложный, подробный отзыв поможет нам сделать его лучше;
  • изучите вопросы других учеников и ответы на них. Это база знаний, которой можно и нужно пользоваться.
Об обучении на Хекслете

Для полного доступа к курсу нужна профессиональная подписка

Профессиональная подписка откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
900
упражнения
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно.

  • 120 курсов, 2000+ часов теории
  • 900 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы соглашаетесь c «Политикой конфиденциальности» и «Условиями оказания услуг»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы

С нуля до разработчика. Возвращаем деньги, если не удалось найти работу.

Иконка программы Node.js-разработчик
Профессия
Разработка бэкенд-компонентов веб-приложений
22 сентября 8 месяцев

Есть вопрос или хотите участвовать в обсуждении?

Зарегистрируйтесь или войдите в свой аккаунт

Отправляя форму, вы соглашаетесь c «Политикой конфиденциальности» и «Условиями оказания услуг»