Создание веб-сервера в Node.js с помощью модуля HTTP часть 1

Создание веб-сервера в Node.js с помощью модуля HTTP часть 1

AlexxSafonov

https://t.me/AlexxSafonov

Шаг 1 — Создание базового сервера HTTP

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

Прежде всего нам нужно настроить доступную среду программирования для выполнения наших упражнений, а также других заданий в настоящей статье. Создайте в терминале папку с именем first-servers:

$mkdir first-servers

Затем откройте эту папку:

$cd first-servers

Затем создайте файл для кода:

$touch hello.js

Откройте файл в текстовом редакторе. Мы используем редактор nano, потому что он доступен в терминале:

$nano hello.js

Для начала мы загрузим модуль http, входящий в стандартную комплектацию установки Node.js. Добавьте следующую строку в hello.js:

first-servers/hello.js

Модуль http содержит функцию создания сервера, которую мы более детально рассмотрим позднее. 

На следующем шаге мы определим две константы, хост и порт, к которым будет привязан наш сервер

first-servers/hello.js

const host = 'localhost';
const port = 8000;

Как указывалось ранее, веб-серверы принимают запросы из браузеров и других клиентов. Для взаимодействия с веб-сервером обычно вводится доменное имя, которое сервер DNS преобразует в IP-адрес. IP-адрес — это уникальная числовая последовательность, идентифицирующая компьютер в Интернете. 

Значение localhost — это специальный частный адрес, с помощью которого компьютеры ссылаются на себя. Обычно оно эквивалентно внутреннему IP-адресу 127.0.0.1 и доступно только локальному компьютеру, но недоступно Интернету или локальным сетям, к которым подключен компьютер.

Порт — это числовое значение, которое серверы используют как точку доступа или «дверь» к нашему IP-адресу. В нашем примере мы будем использовать для нашего веб-сервера порт 8000. Порты 8080 и 8000 обычно используются при разработке как порты по умолчанию, и в большинстве случаев разработчики предпочитают использовать именно эти порты для серверов HTTP.

Когда мы привяжем наш сервер к этому хосту и порту, мы сможем подключаться к нашему серверу, открывая адрес http://localhost:8000 в локальном браузере.

Добавим специальную функцию, которую в Node.js мы называем прослушиватель запросов. Эта функция предназначена для обработки входящих запросов HTTP и возврата ответа HTTP. Данная функция должна иметь два аргумента, объект запроса и объект ответа. Объект запроса записывает все данные поступающего запроса HTTP. Объект ответа используется для возвращения серверу ответов HTTP.

Нам нужно, чтобы наш первый сервер возвращал следующее сообщение при попытке доступа к нему: "My first server!".

Добавим эту функцию:

first-servers/hello.js

const requestListener = function (req, res) {
    res.writeHead(200);
    res.end("My first server!");
};

Названия функций обычно описывают их назначение. Например, если мы создаем функцию прослушивателя запросов для вывода списка книг, мы назовем ее listBooks(). Поскольку мы рассматриваем общий пример, мы используем для него общее имя requestListener.

Все функции прослушивания запросов в Node.js принимают два аргумента, req и res (мы можем присвоить им другие имена, если захотим). Отправляемый пользователем запрос HTTP записывается в объекте Request, который соответствует первому аргументу, req. Отправляемый пользователю ответ HTTP формируется посредством взаимодействия с объектом Response во втором аргументе, res.

Первая строка res.writeHead(200); задает код состояния HTTP для ответа. Коды состояния HTTP показывают, насколько хорошо запрос HTTP обработан сервером. В данном случае код состояния 200 соответствует результату "OK"

Следующая строка функции, res.end("My first server!") ;, записывает ответ HTTP на клиент, который его запросил. Эта функция возвращает любые данные, которые должен возвращать сервер. В этом случае будут возвращаться текстовые данные.

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

first-servers/hello.js

const server = http.createServer(requestListener);
server.listen(port, host, () => {
    console.log(`Server is running on http://${host}:${port}`);
});

Сохраните код и закройте nano, нажав CTRL+X.

В первой строке мы создали новый объект server с помощью функции createServer() модуля http. Этот сервер принимает запросы HTTP и передает их нашей функции requestListener().

После создания сервера мы должны привязать его к сетевому адресу. Для этого мы используем метод server.listen(). Он принимает три аргумента: porthost и функцию обратного вызова, срабатывающую, когда сервер начинает прослушивание.

Все эти аргументы необязательные, но всегда лучше прямо указать, какие порт и хост должен использовать веб-сервер. При развертывании веб-серверов в разных средах важно знать порт и хост, чтобы настроить балансировку нагрузки или псевдоним DNS.

Функция обратного вызова регистрирует в нашей консоли сообщение о том, когда сервер начал прослушивать соединения.

Примечание. Хотя requestListener() не использует объект req, он должен быть первым аргументом функции.

Мы создали веб-сервер, написав менее пятнадцати строк кода. Проверим его работу, запустив программу:

$node hello.js

Мы увидим в консоли следующее:

Output
Server is running on http://localhost:8000

Обратите внимание, что командная строка исчезает. Это связано с тем, что сервер Node.js — это постоянно работающий процесс. Он закрывается только при обнаружении ошибки, вызывающей сбой и завершение работы, или когда мы останавливаем процесс Node.js, запускающий сервер.

Мы используем отдельное окно терминала для взаимодействия с сервером с помощью cURL, инструмента командной строки для обмена данными с сетью. Введите команду для отправки запроса HTTP GET на запущенный нами сервер:

curl http://localhost:8000

При нажатии клавиши ENTER на терминале появится следующее:

Output
My first server!

Мы настроили сервер и получили от него первый ответ.

Теперь давайте подробнее разберемся с тем, что произошло во время тестирования сервера. Мы использовали cURL для отправки запроса GET на сервер с адресом http://localhost:8000. Наш сервер Node.js прослушивал соединения этого адреса. Сервер передал запрос функции requestListener(). Функция вернула текстовые данные с кодом состояния 200. Сервер отправил ответ в cURL, и на нашем терминале появилось сообщение.

Прежде чем продолжить, нажмем CTRL+C и закроем запущенный сервер. Это прервет работу сервера и вернет нас в командную строку.

Большинство сайтов и API не используют для ответов формат обычного текста. Страницы HTML и данные JSON —наиболее распространенные форматы ответов. На следующем шаге мы узнаем, как возвращать ответы HTTP в распространенных форматах данных, которые мы встречаем в Интернете.

Шаг 2 — Возврат разных типов контента

Возвращаемый веб-сервером ответ может иметь разные форматы. Мы уже упоминали JSON и HTML, но также существуют и другие текстовые форматы, в том числе XML и CSV. Кроме того, веб-серверы могут возвращать данные и не в текстовом формате, в том числе файлы PDF, архивы zip, аудио- и видеофайлы.

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

  • JSON
  • CSV
  • HTML

Все эти три типа данных основаны на текстовом формате и очень часто используются для распространения контента в Интернете. Многие инструменты и языки разработки для серверов поддерживают возврат этих типов данных. В контексте Node.js нам необходимы две вещи:

  1. Задать для заголовка Content-Type в ответах HTTP подходящее значение.
  2. Убедиться, что res.end() получает данные в правильном формате.

Посмотрим примеры в действии. Код, который мы будем писать в этом и следующих разделах, будет очень похож на уже написанный нами код. Большинство изменений существуют в функции requestListener(). Давайте создадим файлы с этим кодом шаблона, чтобы упростить работу в следующих разделах.

Создайте новый файл с именем html.js. Этот файл будет использоваться позднее для возврата текста HTML в ответе HTTP. Здесь мы введем код шаблона и скопируем его в другие серверы, возвращающие разные типы.

Введите в терминале следующее:

touch html.js

Copy

Теперь откройте этот файл в текстовом редакторе:

nano html.js

Copy

Скопируем код шаблона. Введите в nano следующее:

first-servers/html.js

const http = require("http");

const host = 'localhost';
const port = 8000;

const requestListener = function (req, res) {};

const server = http.createServer(requestListener);
server.listen(port, host, () => {
    console.log(`Server is running on http://${host}:${port}`);
});

Copy

Сохраните файл html.js и закройте его с помощью CTRL+X, а затем вернитесь в терминал.

Теперь скопируем этот файл в два новых файла. Первый файл будет возвращать данные CSV в ответе HTTP:

cp html.js csv.js

Copy

Второй файл будет возвращать ответ JSON на сервере:

cp html.js json.js

Copy

Остальные файлы будут предназначены для последующих упражнений:

cp html.js htmlFile.js
cp html.js routes.js

Copy

Теперь мы готовы продолжить наши упражнения. Начнем с возврата JSON.

Вывод JSON

Нотация объектов JavaScript (JSON) представляет собой текстовый формат обмена данными. Как предполагает его название, данный формат основан на объектах JavaScript, но при этом он не зависит от языка, то есть его может использовать любой язык программирования, способный парсить его синтаксис.

Формат JSON обычно используется API для приема и возврата данных. Его популярность обусловлена меньшим размером, чем у XML и других форматов обмена данными, а также наличием инструментов для парсинга его синтаксиса без излишних усилий. Если вы хотите узнать больше о JSON, вы можете прочитать наше руководство Работа с JSON в JavaScript.

Откройте файл json.js с помощью nano:

nano json.js

Copy

Нам нужно вернуть ответ JSON. Изменим функцию requestListener() для возврата соответствующего заголовка для всех ответов JSON посредством изменения выделенных строк:

first-servers/json.js

...
const requestListener = function (req, res) {
    res.setHeader("Content-Type", "application/json");
};
...

Copy

Метод res.setHeader() добавляет заголовок HTTP к ответу. Заголовки HTTP содержат дополнительную информацию, которая может быть прикреплена к запросу или ответу. Метод res.setHeader() принимает два аргумента: название заголовка и его значение.

Заголовок Content-Type используется для указания формата данных, который также называется типом носителя и отправляется с запросом или ответом. В этом случае Content-Type имеет значение application/json.

Возвратим пользователю контент JSON. Изменим json.js следующим образом:

first-servers/json.js

...
const requestListener = function (req, res) {
    res.setHeader("Content-Type", "application/json");
    res.writeHead(200);
    res.end(`{"message": "This is a JSON response"}`);
};
...

Copy

Как и ранее, мы сообщаем пользователю об успешном выполнении запроса, возвращая статус 200. Теперь наш аргумент строки в вызове response.end() содержит корректный код JSON.

Сохраните и закройте json.js, нажав CTRL+X. Запустим сервер с помощью команды node:

node json.js

Copy

Подключимся к серверу в другом терминале, используя cURL:

curl http://localhost:8000

Copy

Нажав ENTER, мы увидим следующий результат:

Output
{"message": "This is a JSON response"}

Нам удалось успешно вывести ответ JSON, как и во многих популярных API для создания приложений. Обязательно закройте работающий сервер, нажав CTRL+C, чтобы вернуться в стандартную командную строку терминала. Теперь перейдем к CSV, другому популярному формату вывода данных.

Обслуживание CSV

Формат разделенных запятой значений (CSV) — это стандартный текстовый формат вывода табличных данных. В большинстве случаев строки разделяются символами новой строки, а элементы внутри строки разделяются запятым.

Откройте файл csv.js в нашем рабочем пространстве с помощью текстового редактора:

nano csv.js

Copy

Добавим следующие строки в функцию requestListener():

first-servers/csv.js

...
const requestListener = function (req, res) {
    res.setHeader("Content-Type", "text/csv");
    res.setHeader("Content-Disposition", "attachment;filename=oceanpals.csv");
};
...

Copy

Теперь Content-Type имеет значение text/csv, соответствующее формату файлов CSV. Также мы добавим заголовок Content-Disposition. Этот заголовок указывает браузеру способ отображения данных, особенно в браузере или в отдельном файле.

При возврате ответов CSV большинство современных браузеров автоматически загружают файл, даже если заголовок Content-Disposition не установлен. Однако при возврате файла CSV этот заголовок нужно добавить, поскольку он позволяет нам задать имя файла CSV. Мы сообщаем браузеру, что файл CSV является вложением, и что его следует загрузить. Затем мы сообщаем браузеру, что файлу присвоено имя oceanpals.csv.

Запишем данные CSV в ответе HTTP:

first-servers/csv.js

...
const requestListener = function (req, res) {
    res.setHeader("Content-Type", "text/csv");
    res.setHeader("Content-Disposition", "attachment;filename=oceanpals.csv");
    res.writeHead(200);
    res.end(`id,name,email\n1,Sammy Shark,shark@ocean.com`);
};
...

Copy

Как и раньше, мы возвращаем статус 200/OK в нашем ответе. Теперь наш вызов res.end() содержит строку корректного файла CSV. Значения в каждом столбце разделяются запятыми, а строки разделяются символом новой строки (\n). У нас имеется две строки, одна для заголовка таблицы, а другая — для данных.

Протестируем этот сервер в браузере. Сохраните файл csv.js и закройте редактор, нажав CTRL+X.

Запустите сервер с помощью команды Node.js:

node csv.js

Copy

Откроем сервер в другом терминале с помощью cURL:

curl http://localhost:8000

Copy

На консоли появится следующее:

Output
id,name,email
1,Sammy Shark,shark@ocean.com

Если мы откроем в браузере адрес http://localhost:8000, загрузится файл CSV. Файл будет иметь имя oceanpals.csv.

Закройте работающий сервер, нажав CTRL+C для возврата в стандартную командную строку терминала.

Мы рассмотрели возврат данных в форматах JSON и CSV, которые часто используются в API. Теперь перейдем к возврату данных сайтов, просматриваемых людьми в браузере.

Обслуживание кода HTML

Гипертекстовый язык разметки (HTML) — самый распространенный формат, используемый пользователями при взаимодействии с серверами через браузер. Он был создан для структурирования веб-контента. Браузеры разработаны для отображения контента в формате HTML, оформленного с использованием стилей CSS, еще одной клиентской веб-технологии для настройки внешнего вида сайтов.

Откроем файл html.js в текстовом редакторе еще раз:

nano html.js

Copy

Изменим функцию requestListener() так, чтобы она возвращала подходящий заголовок Content-Type для ответа HTML:

first-servers/html.js

...
const requestListener = function (req, res) {
    res.setHeader("Content-Type", "text/html");
};
...

Copy

Возвратим пользователю контент HTML. Добавьте в файл html.js выделенные строки, чтобы он выглядел следующим образом:

first-servers/html.js

...
const requestListener = function (req, res) {
    res.setHeader("Content-Type", "text/html");
    res.writeHead(200);
    res.end(`<html><body><h1>This is HTML</h1></body></html>`);
};
...

Copy

Вначале мы добавляем код состояния HTTP. Затем мы вызываем response.end() с аргументом строки, содержащим корректный код HTML. Открывая сервер в браузере, мы увидим страницу HTML с одним тегом заголовка со значением This is HTML.

Сохраним файл и закроем редактор, нажав CTRL+X. Запустим сервер с помощью команды node:

node html.js

Copy

После запуска программы мы увидим сообщение Server is running on http://localhost:8000.

Откройте в браузере адрес http://localhost:8000. Страница будет выглядеть следующим образом:

Изображение ответа HTML, возвращаемого сервером Node.js


Закроем работающий сервер, нажав CTRL+C для возврата в стандартную командную строку терминала.

Код HTML часто добавляется в файл отдельно от серверного кода, такого как наши программы Node.js. Посмотрим, как можно выводить ответы HTML из файлов.

Часть 2

Код на гит хаб



Report Page