One place for hosting & domains

      How To Configure Apache HTTP with MPM Event and PHP-FPM on Ubuntu 18.04


      The author selected the COVID-19 Relief Fund to receive a donation as part of the Write for DOnations program.

      Introduction

      The Apache HTTP web server has evolved through the years to work in different environments and solve different needs. One important problem Apache HTTP has to solve, like any web server, is how to handle different processes to serve an http protocol request. This involves opening a socket, processing the request, keeping the connection open for a certain period, handling new events occurring through that connection, and returning the content produced by a program made in a particular language (such as PHP, Perl, or Python). These tasks are performed and controlled by a Multi-Processing Module (MPM).

      Apache HTTP comes with three different MPM:

      • Pre-fork: A new process is created for each incoming connection reaching the server. Each process is isolated from the others, so no memory is shared between them, even if they are performing identical calls at some point in their execution. This is a safe way to run applications linked to libraries that do not support threading—typically older applications or libraries.
      • Worker: A parent process is responsible for launching a pool of child processes, some of which are listening for new incoming connections, and others are serving the requested content. Each process is threaded (a single thread can handle one connection) so one process can handle several requests concurrently. This method of treating connections encourages better resource utilization, while still maintaining stability. This is a result of the pool of available processes, which often has free available threads ready to immediately serve new connections.
      • Event: Based on worker, this MPM goes one step further by optimizing how the parent process schedules tasks to the child processes and the threads associated to those. A connection stays open for 5 seconds by default and closes if no new event happens; this is the keep-alive directive default value, which retains the thread associated to it. The Event MPM enables the process to manage threads so that some threads are free to handle new incoming connections while others are kept bound to the live connections. Allowing re-distribution of assigned tasks to threads will make for better resource utilization and performance.

      The MPM Event module is a fast multi-processing module available on the Apache HTTP web server.

      PHP-FPM is the FastCGI Process Manager for PHP. The FastCGI protocol is based on the Common Gateway Interface (CGI), a protocol that sits between applications and web servers like Apache HTTP. This allows developers to write applications separately from the behavior of web servers. Programs run their processes independently and pass their product to the web server through this protocol. Each new connection in need of processing by an application will create a new process.

      By combining the MPM Event in Apache HTTP with the PHP FastCGI Process Manager (PHP-FPM) a website can load faster and handle more concurrent connections while using fewer resources.

      In this tutorial you will improve the performance of the LAMP stack by changing the default multi-processing module from pre-fork to event and by using the PHP-FPM process manager to handle PHP code instead of the classic mod_php in Apache HTTP.

      Prerequisites

      Before you begin this guide you’ll need the following:

      Step 1 — Changing the Multi-Processing Module

      Ubuntu inherits scripts to enable or disable Apache HTTP modules from its parent distribution, Debian. You’ll use this toolset in this step to disable the Pre-fork module and enable the Event module.

      In this step you will stop Apache HTTP, disable the PHP 7.2 module linked to the Pre-fork module, and then disable Pre-fork to immediately enable the Event module.

      First you’ll stop the Apache HTTP service:

      • sudo systemctl stop apache2

      Now you can disable the PHP 7.2 module, which is related to the Pre-fork module:

      Then disable the Pre-fork MPM module:

      • sudo a2dismod mpm_prefork

      Now enable the Event MPM module:

      You’ve switched the MPM from pre-fork to event and removed the PHP 7.2 module connection between PHP and Apache HTTP. In the next step you’ll install the php-fpm module, as well as the related libraries and proxy modules. You’ll configure Apache HTTP so that it can communicate with PHP too.

      Step 2 — Configuring Apache HTTP to Use the FastCGI Process Manager

      At this stage you’ve switched the way Apache HTTP processes connections by moving from the Pre-fork MPM to Event. However along the way you’ve disabled the PHP module that connected Apache HTTP with any program running on PHP.

      In this step you’ll install the PHP-FPM processor so Apache HTTP is again able to process PHP programs. And you’ll also install the dependency libraries and enable the modules so both can cooperate smoothly and quicker than before.

      First install php-fpm. The following command will install the PHP-FPM package and it will automatically enable the php7.2-fpm service integrated with systemd, so the service is started at boot time:

      In order to communicate, Apache HTTP and PHP need a library enabling that capacity. You’ll now install libapache2-mod-fcgid, which is able to serve as an interface between programs with web servers, and it’s specific to Apache HTTP. This communication will happen through a UNIX socket.

      Install this library:

      • sudo apt install libapache2-mod-fcgid

      You’ve installed php-fpm and the libapache2-mod-fcgid, but neither are enabled yet.

      First enable the php-fpm module with the following command:

      Second enable Apache HTTP proxy module:

      Third enable the FastCGI proxy module in Apache HTTP:

      Note: You can read the configuration of this interaction between PHP programs and Apache HTTP through a UNIX socket with the following:

      • cat /etc/apache2/conf-enabled/php7.2-fpm.conf

      Everything is now in place so you can start Apache HTTP. You’ll make a configuration check first:

      • sudo apachectl configtest

      Output

      Syntax OK

      After that you can proceed to restart Apache HTTP, since it was automatically started when installing the FastCGI library libapache2-mod-fcgid:

      • sudo systemctl restart apache2

      You’ve installed the php-fpm module, configured Apache HTTP to work with it, enabled the necessary modules for the FastCGI protocol to work, and started the corresponding services.

      Now that Apache has the Event MPM module enabled and PHP-FPM is present and running, it is time to check everything is working as intended.

      Step 3 — Checking Your Configuration

      In order to check that the configuration changes have been applied you’ll run some tests. The first one will check what multi-processing module Apache HTTP is using. The second will verify that PHP is using the FPM manager.

      Check the Apache HTTP server by running the following command:

      • sudo apachectl -M | grep 'mpm'

      Your output will be as follows:

      Output

      mpm_event_module (shared)

      You can repeat the same for the proxy module and FastCGI:

      • sudo apachectl -M | grep 'proxy'

      The output will show:

      Output

      proxy_module (shared) proxy_fcgi_module (shared)

      If you would like to see the entire list of the modules, you can remove the the second part of the command after -M.

      It is now time to check if PHP is using the FastCGI Process Manager. To do so you’ll write a small PHP script that will show you all the information related to PHP.

      Run the following command to write a file named as follows:

      • sudo nano /var/www/your_domain/info.php

      Add the following content into the info.php file:

      info.php

      <?php phpinfo(); ?>
      

      Now visit your server’s URL and append info.php at the end like so: http://your_domain/info.php.

      The server API entry will be FPM/FastCGI.

      PHP Screen the Server API entry FPM/FastCGI

      Delete the info.php file after this check so no information about the server is publicly disclosed:

      • sudo rm /var/www/yourdomain.com/info.php

      You’ve checked the working status of the MPM module, the modules handling the FastCGI and the handling of PHP code.

      Conclusion

      You’ve optimized your original LAMP stack, so the number of connections to create new Apache HTTP processes has increased, PHP-FPM will handle PHP code more efficiently, and overall resource utilization has improved.

      See the Apache HTTP server project documentation for more information on the different modules and related projects.



      Source link

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


      Автор выбрал COVID-19 Relief Fund для получения пожертвования в рамках программы Write for DOnations.

      Введение

      При просмотре веб-страницы в браузере мы отправляем запрос на другой компьютер в Интернете, который отправляет в ответ веб-страницу. Компьютер, с которым вы взаимодействуете через Интернет, называется веб-сервером. Веб-сервер получает запросы HTTP от клиентов, в том числе от вашего браузера, и отправляет им ответы HTTP, например страницы HTML или код JSON из API.

      Для вывода веб-страницы сервер использует разнообразное программное обеспечение. Программное обеспечение может быть клиентским или серверным. Клиентское программное обеспечение отвечает за вывод контента, например за цвета панели навигации и стили текста. Серверное программное обеспечение отвечает за обмен, обработку и хранение данных. За обработку сетевых запросов вашего браузера и взаимодействие с базами данных в основном отвечает серверный код.

      Node.js позволяет разработчикам использовать JavaScript для создания серверного кода, хотя традиционно этот язык использовался в браузере для создания клиентского кода. Объединение клиентского и серверного кода в одной среде разработки упрощает создание веб-серверов, и именно поэтому Node.js стал популярным инструментом для написания серверного кода.

      В этом обучающем руководстве мы научимся создавать веб-серверы с помощью модуля http, входящего в состав Node.js. Мы создадим веб-серверы, которые смогут возвращать данные JSON, файлы CSV и веб-страницы HTML.

      Предварительные требования

      • Убедитесь, что на используемом для разработки компьютере установлен Node.js. Для целей этого обучающего руководства мы используем версию Node.js 10.19.0. Чтобы установить его в macOS или Ubuntu 18.04, следуйте указаниям руководства Установка Node.js и создание локальной среды разработки в macOS или раздела Установка с помощью PPA руководства Установка Node.js в Ubuntu 18.04.
      • Платформа Node.js позволяет создавать готовые веб-серверы. Для начала вам следует познакомиться с основами Node.js. Для этого вы можете воспользоваться нашим руководством Написание и запуск первой программы на Node.js.
      • Также мы посвятим один из разделов этого обучающего руководства асинхронному программированию. Если вы незнакомы с асинхронным программированием в Node.js или с модулем fs для взаимодействия с файлами, вы можете узнать о них больше из нашей статьи Написание асинхронного кода в Node.js.

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

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

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

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

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

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

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

      first-servers/hello.js

      const http = require("http");
      

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

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

      first-servers/hello.js

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

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

      Значение 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". Если вы хотите узнать больше о различных кодах HTTP, которые могут возвращать ваши веб-серверы, и о значении этих кодов, начните с нашего руководства Диагностика распространенных кодов ошибок HTTP.

      Следующая строка функции, 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(). Он принимает три аргумента: port, host и функцию обратного вызова, срабатывающую, когда сервер начинает прослушивание.

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

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

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

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

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

      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, аудио- и видеофайлы.

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

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

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

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

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

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

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

      Скопируем код шаблона. Введите в 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}`);
      });
      

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

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

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

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

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

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

      Вывод JSON

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

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

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

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

      first-servers/json.js

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

      Метод 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"}`);
      };
      ...
      

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

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

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

      • curl http://localhost:8000

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

      Output

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

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

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

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

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

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

      first-servers/csv.js

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

      Теперь 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,emailn1,Sammy Shark,shark@ocean.com`);
      };
      ...
      

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

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

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

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

      • curl http://localhost:8000

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

      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 в текстовом редакторе еще раз:

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

      first-servers/html.js

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

      Возвратим пользователю контент 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>`);
      };
      ...
      

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

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

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

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

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

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

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

      Шаг 3 — Вывод страницы HTML из файла

      Код HTML можно выводить пользователю в виде строк Node.js, но желательно загружать файлы HTML и выводить их содержимое. Так нам не нужно хранить длинные строки кода HTML в файле Node.js, за счет чего код становится более компактным, и мы получаем возможность независимо работать с разными частями сайта. Такая концепция разделения часто используется в веб-разработке, поэтому важно знать, как правильно загружать файлы HTML для их поддержки в Node.js.

      Для вывода файлов HTML мы загружаем их с помощью модуля fs и используем их данные при написании ответа HTTP.

      Вначале создадим файл HTML, который будет возвращать наш веб-сервер. Создайте новый файл HTML:

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

      Наша веб-страница будет минимальной. Она будет иметь оранжевый фон и содержать текст приветствия в центре. Добавьте в файл следующий код:

      first-servers/index.html

      <!DOCTYPE html>
      
      <head>
          <title>My Website</title>
          <style>
              *,
              html {
                  margin: 0;
                  padding: 0;
                  border: 0;
              }
      
              html {
                  width: 100%;
                  height: 100%;
              }
      
              body {
                  width: 100%;
                  height: 100%;
                  position: relative;
                  background-color: rgb(236, 152, 42);
              }
      
              .center {
                  width: 100%;
                  height: 50%;
                  margin: 0;
                  position: absolute;
                  top: 50%;
                  left: 50%;
                  transform: translate(-50%, -50%);
                  color: white;
                  font-family: "Trebuchet MS", Helvetica, sans-serif;
                  text-align: center;
              }
      
              h1 {
                  font-size: 144px;
              }
      
              p {
                  font-size: 64px;
              }
          </style>
      </head>
      
      <body>
          <div class="center">
              <h1>Hello Again!</h1>
              <p>This is served from a file</p>
          </div>
      </body>
      
      </html>
      

      На этой веб-странице отображается две строки текста: Hello Again! и This is served from a file. Строки отображаются друг над другом в центре страницы. Первая строка текста отображается как заголовок, то есть она будет больше. Вторая строка текста будет немного меньше. Весь текст будет выводиться белым цветом на оранжевом фоне страницы.

      Хотя это не относится к настоящей статье и серии статей, вы можете узнать больше об HTML, CSS и других технологиях создания веб-клиентов с помощью руководства Введение в веб-технологии от Mozilla.

      Это весь код HTML, который нам нужен, так что теперь можно сохранить и закрыть файл, нажав CTRL+X. Теперь мы можем перейти к коду сервера.

      В этом упражнении мы будем работать с файлом htmlFile.js. Откройте этот файл в текстовом редакторе:

      Поскольку нам нужно прочитать файл, для начала импортируем модуль fs:

      first-servers/htmlFile.js

      const http = require("http");
      const fs = require('fs').promises;
      ...
      

      Этот модуль содержит функцию readFile(), которую мы будем использовать для загрузки файла HTML. Мы импортируем вариант обещания в соответствии с современными передовыми практиками работы с JavaScript. Мы используем обещания, поскольку с синтаксической точки зрения они лучше функций обратного вызова, к которым нам пришлось бы прибегнуть, если бы мы назначили fs как require('fs'). Дополнительную информацию о лучших практиках асинхронного программирования можно найти в нашем руководстве Написание асинхронного кода в Node.js.

      Нам нужно, чтобы при отправке пользователем запроса к системе считывался наш файл HTML. Для начала изменим requestListener() для чтения файла:

      first-servers/htmlFile.js

      ...
      const requestListener = function (req, res) {
          fs.readFile(__dirname + "/index.html")
      };
      ...
      

      Мы используем метод fs.readFile() для загрузки файла. Он использует аргумент __dirname + "/index.html". Специальная переменная __dirname содержит абсолютный путь к директории запуска кода Node.js. В конце мы добавляем /index.html, чтобы мы могли загрузить ранее созданный файл HTML.

      Возвратим страницу HTML после ее загрузки:

      first-servers/htmlFile.js

      ...
      const requestListener = function (req, res) {
          fs.readFile(__dirname + "/index.html")
              .then(contents => {
                  res.setHeader("Content-Type", "text/html");
                  res.writeHead(200);
                  res.end(contents);
              })
      };
      ...
      

      Если обещание fs.readFile() успешно выполняется, оно возвращает свои данные. Для этого случая мы используем метод then(). Параметр contents содержит данные файла HTML.

      Вначале мы задаем для заголовка Content-Type значение text/html, чтобы сообщить клиенту, что мы возвращаем данные HTML. Затем мы пишем код состояния, показывая, что запрос выполнен успешно. В заключение мы отправляем на клиент загруженную страницу HTML с данными в переменной contents.

      Иногда метод fs.readFile() может выполняться с ошибками, и нам нужно предусмотреть подобные случаи. Добавьте в функцию requestListener() следующее:

      first-servers/htmlFile.js

      ...
      const requestListener = function (req, res) {
          fs.readFile(__dirname + "/index.html")
              .then(contents => {
                  res.setHeader("Content-Type", "text/html");
                  res.writeHead(200);
                  res.end(contents);
              })
              .catch(err => {
                  res.writeHead(500);
                  res.end(err);
                  return;
              });
      };
      ...
      

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

      Когда в обещании возникает ошибка, оно отклоняется. Эта ситуация обрабатывается с помощью метода catch(). Он принимает ошибку, возвращаемую fs.readFile(), устанавливает код состояния 500, сигнализирующий о внутренней ошибке, и возвращает пользователю сообщение об ошибке.

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

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

      Изображение страницы HTML, загруженной из файла в Node.js

      Мы вывели пользователю страницу HTML с сервера. Теперь мы можем закрыть запущенный сервер, нажав CTRL+C. Сделав это, мы увидим командную строку терминала.

      При написании такого кода в производственной среде не всегда желательно загружать страницу HTML при каждом получении запроса HTTP. В нашем случае страница HTML занимает всего 800 байт, но на сложных сайтах размер страниц может доходить до нескольких мегабайт. Загрузка больших файлов занимает много времени. Если на вашем сайте ожидается большой трафик, лучше всего загружать файлы HTML при запуске и сохранять их содержимое. После их загрузки вы можете настроить сервер так, чтобы он прослушивал запросы адреса.

      Чтобы продемонстрировать этот метод, покажем, как можно сделать сервер более эффективным и масштабируемым.

      Эффективный вывод кода HTML

      Вместо того чтобы загружать страницу HTML для каждого запроса, мы загрузим ее только один раз, в самом начале. Запрос будет возвращать данные, загруженные нами при запуске.

      Откройте в терминале скрипт Node.js с помощью текстового редактора:

      Добавим новую переменную, прежде чем создавать функцию requestListener():

      first-servers/htmlFile.js

      ...
      let indexFile;
      
      const requestListener = function (req, res) {
      ...
      

      При запуске программы эта переменная будет хранить содержимое файла HTML.

      Изменим функцию requestListener(). Теперь вместо загрузки файла она будет возвращать содержимое indexFile:

      first-servers/htmlFile.js

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

      Далее мы изменим логику чтения файла с функции requestListener() на момент запуска нашего сервера. Внесите следующие изменения при создании сервера:

      first-servers/htmlFile.js

      ...
      
      const server = http.createServer(requestListener);
      
      fs.readFile(__dirname + "/index.html")
          .then(contents => {
              indexFile = contents;
              server.listen(port, host, () => {
                  console.log(`Server is running on http://${host}:${port}`);
              });
          })
          .catch(err => {
              console.error(`Could not read index.html file: ${err}`);
              process.exit(1);
          });
      

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

      Код, считывающий файл, похож на написанный нами при первой попытке. Однако при успешном чтении файла мы можем сохранить его содержимое в глобальной переменной indexFile. Мы запустим сервер с методом listen(). Главное — загрузить файл до запуска сервера. Так функция requestListener() гарантированно возвращает страницу HTML, поскольку переменная indexFile больше не пустая.

      Блок обработки ошибок также изменился. Если файл не удается загрузить, мы записываем ошибку и выводим ее на консоль. Затем мы закрываем программу Node.js с помощью функции exit() без запуска сервера. Так мы видим, почему не удалось прочитать файл, и можем решить проблему и снова запустить сервер.

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

      Шаг 4 — Управление маршрутами с использованием объекта HTTP Request

      Большинство посещаемых нами сайтов и используемых нами API имеют несколько конечных точек, что позволяет получать доступ к разным ресурсам. Хорошим примером является система управления книгами, которая может использоваться в библиотеке. Ей нужно будет не только управлять данными книг, но и управлять данными авторов для составления каталогов и обеспечения удобства поиска.

      Хотя данные книг и авторов связаны, они представляют собой разные объекты. В подобных случаях разработчики обычно программируют каждый объект для разных конечных точек, чтобы показать пользователю API, с какими данными он взаимодействует.

      Создадим новый сервер для небольшой библиотеки, который будет возвращать два разных типа данных. Если пользователь откроет адрес сервера с /books, он получит список книг в формате JSON. Если пользователь откроет раздел /authors, он получит список с информацией об авторах в формате JSON.

      До сих пор мы возвращали одинаковые ответы на каждый получаемый запрос. Рассмотрим небольшой пример.

      Запустим заново наш пример с ответом JSON:

      Отправим на другом терминале запрос cURL, как мы делали ранее:

      • curl http://localhost:8000

      Вы увидите следующее:

      Output

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

      Теперь попробуем другую команду curl:

      • curl http://localhost:8000/todos

      После нажатия Enter вы увидите тот же самый результат:

      Output

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

      Мы не встраивали в функцию requestListener() никакую специальную логику дял обработки запроса, URL которого содержит /todos, и поэтому Node.js по умолчанию возвращает то же сообщение JSON.

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

      Для начала закройте сервер, нажав CTRL+C.

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

      Начнем с сохранения наших данных JSON в переменных перед функцией requestListener():

      first-servers/routes.js

      ...
      const books = JSON.stringify([
          { title: "The Alchemist", author: "Paulo Coelho", year: 1988 },
          { title: "The Prophet", author: "Kahlil Gibran", year: 1923 }
      ]);
      
      const authors = JSON.stringify([
          { name: "Paulo Coelho", countryOfBirth: "Brazil", yearOfBirth: 1947 },
          { name: "Kahlil Gibran", countryOfBirth: "Lebanon", yearOfBirth: 1883 }
      ]);
      ...
      

      Переменная books — это строка, содержащая данные JSON для массива объектов книг. Каждая книга имеет заголовок или название, автора и год издания.

      Переменная authors — это строка, содержащая данные JSON для массива объектов авторов. Каждый автор имеет имя, страну рождения и год рождения.

      Теперь у нас имеются данные для ответов, и мы можем начать изменение функции requestListener() для использования желаемых маршрутов.

      Вначале нужно убедиться, что все ответы нашего сервера будут иметь правильный заголовок Content-Type:

      first-servers/routes.js

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

      Далее нам нужно возвращать подходящие данные JSON в зависимости от URL, используемого пользователем. Создадим выражение switch для URL запроса:

      first-servers/routes.js

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

      Чтобы получить путь URL от объекта request, нам потребуется доступ к его свойству url. Теперь мы можем добавить в выражение switch варианты для возврата подходящего кода JSON.

      Выражение switch в JavaScript позволяет определять, какой код будет выполняться в зависимости от значения объекта или выражения JavaScript (например, от результата математической операции). Если вы не знаете или забыли, как использовать такие выражения, воспользуйтесь нашим руководством Использование выражения switch в JavaScript.

      Продолжим и добавим вариант, когда пользователь хочет получить список книг:

      first-servers/routes.js

      ...
      const requestListener = function (req, res) {
          res.setHeader("Content-Type", "application/json");
          switch (req.url) {
              case "/books":
                  res.writeHead(200);
                  res.end(books);
                  break
          }
      }
      ...
      

      Мы устанавливаем код состояния 200, указывая, что запрос обработан правильно, и возвращаем данные JSON, содержащие список книг. Добавим еще один вариант для авторов:

      first-servers/routes.js

      ...
      const requestListener = function (req, res) {
          res.setHeader("Content-Type", "application/json");
          switch (req.url) {
              case "/books":
                  res.writeHead(200);
                  res.end(books);
                  break
              case "/authors":
                  res.writeHead(200);
                  res.end(authors);
                  break
          }
      }
      ...
      

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

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

      routes.js

      ...
      const requestListener = function (req, res) {
          res.setHeader("Content-Type", "application/json");
          switch (req.url) {
              case "/books":
                  res.writeHead(200);
                  res.end(books);
                  break
              case "/authors":
                  res.writeHead(200);
                  res.end(authors);
                  break
              default:
                  res.writeHead(404);
                  res.end(JSON.stringify({error:"Resource not found"}));
          }
      }
      ...
      

      Мы используем ключевое слово default в выражении switch, чтобы учесть все остальные сценарии, кроме описанных в предыдущих вариантах. Мы устанавливаем код состояния 404, указывающий, что запрошенный URL не найден. Далее мы задаем объект JSON, содержащий сообщение об ошибке.

      Протестируем поведение нашего сервера. Запустите на другом терминале команду, чтобы проверить, получим ли мы список книг:

      • curl http://localhost:8000/books

      Нажмите Enter, чтобы получить следующий результат:

      Output

      [{"title":"The Alchemist","author":"Paulo Coelho","year":1988},{"title":"The Prophet","author":"Kahlil Gibran","year":1923}]

      Пока все хорошо. Попробуем то же самое для /authors. Введите в терминале следующую команду:

      • curl http://localhost:8000/authors

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

      Output

      [{"name":"Paulo Coelho","countryOfBirth":"Brazil","yearOfBirth":1947},{"name":"Kahlil Gibran","countryOfBirth":"Lebanon","yearOfBirth":1883}]

      В заключение попробуем ввести ошибочный URL, чтобы функция requestListener() вывела сообщение об ошибке:

      • curl http://localhost:8000/notreal

      При вводе этой команды будет выведено следующее сообщение:

      Output

      {"error":"Resource not found"}

      Закройте работающий сервер, нажав CTRL+C.

      Мы создали несколько маршрутов для предоставления пользователям разных данных. Также мы добавили ответ по умолчанию, выводящий сообщение об ошибке HTTP, если пользователь вводит неправильный URL.

      Заключение

      В этом обучающем руководстве мы создали несколько серверов HTTP Node.js. Вначале мы сформировали простой текстовый ответ. Затем мы перешли к возврату с сервера разных типов данных: JSON, CSV и HTML. Затем мы рассмотрели комбинирование загрузки файлов с ответами HTTP для вывода пользователю страниц HTML с сервера и создания API, использующего данные запроса пользователя для определения ответа.

      Теперь вы готовы к созданию веб-серверов, которые смогут обрабатывать разнообразные запросы и ответы. Эти знания помогут вам создать сервер, возвращающий пользователю много разных страниц HTML для разных конечных точек. Также вы можете создавать собственные API.

      Чтобы узнать больше о веб-серверах HTTP в Node.js, вы можете почитать документацию Node.js по модулю http. Если вы хотите продолжить изучение Node.js, возвращайтесь на страницу серии Программирование в Node.js.



      Source link

      Comment créer un serveur Web en Node.js avec le module HTTP


      L’auteur a choisi le COVID-19 Relief Fund pour recevoir un don dans le cadre du programme Write for DOnations.

      Introduction

      Lorsque vous visualisez une page web dans votre navigateur, vous faites une demande à un autre ordinateur sur internet, qui vous fournit alors la page web en réponse. L’ordinateur avec lequel vous parlez via l’internet est un serveur web. Un serveur web reçoit des requêtes HTTP d’un client, comme votre navigateur, et fournit une réponse HTTP, comme une page HTML ou JSON d’une API.

      De nombreux logiciels sont nécessaires pour qu’un serveur renvoie une page web. Ces logiciels se classent généralement en deux catégories : le frontend et le backend. Le code front-end concerne la manière dont le contenu est présenté, comme la couleur d’une barre de navigation et le style du texte.  Le code back-end concerne la manière dont les données sont échangées, traitées et stockées.  Le code qui traite les requêtes réseau de votre navigateur ou qui communique avec la base de données est principalement géré par le code back-end.

      Node.js permet aux développeurs d’utiliser JavaScript pour écrire du code back-end, même si, traditionnellement, il était utilisé dans le navigateur pour écrire du code front-end. Le fait d’avoir le front-end et le back-end ensemble de cette manière réduit l’effort nécessaire pour créer un serveur web, ce qui est une des raisons majeures pour lesquelles Node.js est un choix populaire pour écrire du code back-end.

      Dans ce tutoriel, vous apprendrez comment construire des serveurs web en utilisant le module http qui est inclus dans Node.js. Vous allez construire des serveurs web capables de renvoyer des données JSON, des fichiers CSV et des pages web HTML.

      Conditions préalables

      Étape 1 – Création d’un serveur HTTP de base

      Commençons par créer un serveur qui renvoie du texte en clair à l’utilisateur. Cela couvrira les concepts clés nécessaires à la mise en place d’un serveur, qui fournira la base nécessaire pour retourner des formats de données plus complexes comme JSON.

      Tout d’abord, nous devons mettre en place un environnement de codage accessible pour effectuer nos exercices, ainsi que les autres dans l’article. Dans le terminal, créez un dossier appelé first-servers :

      Entrez ensuite dans ce dossier :

      Maintenant, créez le fichier qui abritera le code :

      Ouvrez le fichier dans un éditeur de texte. Nous utiliserons nano puisqu’il est disponible dans le terminal :

      Nous commençons par charger le module http qui est standard avec toutes les installations de Node.js Ajoutez la ligne suivante à hello.js :

      first-servers/hello.js

      const http = require("http");
      

      Le module http contient la fonction de création du serveur, que nous verrons plus tard. Si vous souhaitez en savoir plus sur les modules dans Node.js, consultez notre article Comment créer un module Node.js.

      Notre prochaine étape consistera à définir deux constantes, l’hôte et le port auxquels notre serveur sera lié :

      first-servers/hello.js

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

      Comme mentionné précédemment, les serveurs web acceptent des requêtes des navigateurs et autres clients. Nous pouvons interagir avec un serveur web en entrant un nom de domaine, qui est traduit en une adresse IP par un serveur DNS. Une adresse IP est une séquence unique de chiffres qui identifie une machine sur un réseau, comme l’internet. Pour plus d’informations sur les concepts de noms de domaine, consultez notre article Introduction à la terminologie, aux composants et aux concepts du DNS.

      La valeur localhost est une adresse privée spéciale que les ordinateurs utilisent pour se désigner eux-mêmes.  Elle est généralement l’équivalent de l’adresse IP interne 127.0.0.1 et n’est disponible que pour l’ordinateur local, et non pour les réseaux locaux que nous avons rejoints ou pour l’internet.

      Le port est un numéro que les serveurs utilisent comme point d’accès ou “porte” à notre adresse IP. Dans notre exemple, nous utiliserons le port 8000 pour notre serveur web. Les ports 8080 et 8000 sont généralement utilisés comme ports par défaut dans le développement, et dans la plupart des cas, les développeurs les utiliseront plutôt que d’autres ports pour les serveurs HTTP.

      Lorsque nous lierons notre serveur à cet hôte et à cet port, nous pourrons atteindre notre serveur en visitant http://localhost:8000 dans un navigateur local.

      Ajoutons une fonction spéciale, que nous appelons dans Node.js un request listener. Cette fonction est destinée à traiter une requête HTTP entrante et à renvoyer une réponse HTTP. Cette fonction doit avoir deux arguments, un objet de requête et un objet de réponse. L’objet de requête capture toutes les données de la requête HTTP entrante. L’objet de réponse est utilisé pour renvoyer des réponses HTTP au serveur.

      Nous voulons que notre premier serveur renvoie ce message chaque fois que quelqu’un y accède : "My first server!"​.

      Ajoutons ensuite cette fonction :

      first-servers/hello.js

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

      La fonction est généralement nommée en fonction de ce qu’elle fait. Par exemple, si nous créons une fonction request listener pour renvoyer une liste de livres, nous la nommerons probablement listBooks(). Comme celui-ci est un exemple, nous utiliserons le nom générique requestListener.

      Toutes les fonctions request listener dans Node.js acceptent deux arguments : req et res (nous pouvons les nommer différemment si nous le voulons). La requête HTTP que l’utilisateur envoie est capturée dans un objet Request, qui correspond au premier argument, req. La réponse HTTP que nous renvoyons à l’utilisateur est formée par l’interaction avec l’objet Response en second argument, res.

      La première ligne res.writeHead(200); définit le code d’état HTTP de la réponse. Les codes d’état HTTP indiquent comment une requête HTTP a été traitée par le serveur. Dans ce cas, le code d’état 200 correspond à "OK". Si vous souhaitez en savoir plus sur les différents codes HTTP que vos serveurs web peuvent renvoyer avec la signification qu’ils revêtent, notre guide Comment dépanner les codes d’erreur HTTP courants est un bon point de départ.

      La ligne suivante de la fonction, res.end("My first server!") ;, renvoie la réponse HTTP au client qui l’a demandée. Cette fonction renvoie toutes les données que le serveur doit renvoyer.  Dans ce cas, elle renvoie des données textuelles.

      Enfin, nous pouvons maintenant créer notre serveur et utiliser notre request listener :

      first-servers/hello.js

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

      Enregistrez et quittez nano en appuyant sur CTRL+X.

      À la première ligne, nous créons un nouvel objet server via la fonction createServer() du module http. Ce serveur accepte les requêtes HTTP et les renvoie à notre fonction requestListener().

      Après avoir créé notre serveur, nous devons le lier à une adresse réseau. Nous le faisons avec la méthode server.listen(). Elle accepte trois arguments : le port, host et une fonction de rappel qui se déclenche lorsque le serveur commence à écouter.

      Tous ces arguments sont facultatifs, mais il est bon d’indiquer explicitement quel port et quel hôte nous voulons qu’un serveur web utilise. Lorsque l’on déploie des serveurs web dans différents environnements, il est nécessaire de connaître le port et l’hôte sur lesquels ils fonctionnent pour mettre en place une répartition de charge ou un alias DNS.

      La fonction de rappel enregistre un message sur notre console afin que nous puissions savoir quand le serveur a commencé à écouter les connexions.

      Remarque : même si requestListener() n’utilise pas l’objet req, il doit toujours être le premier argument de la fonction.

      Avec moins de quinze lignes de code, nous avons maintenant un serveur web. Voyons-le en action et testons-le de bout en bout en exécutant le programme :

      Dans la console, nous verrons cette sortie :

      Output

      Server is running on http://localhost:8000

      Notez que l’invite disparaît. C’est dû au fait qu’un serveur Node.js est un processus de longue durée. Il ne se termine que s’il rencontre une erreur qui le fait planter et quitter, ou si nous arrêtons le processus Node.js qui fait tourner le serveur.

      Dans une fenêtre de terminal séparée, nous communiquerons avec le serveur en utilisant cURL, un outil CLI pour transférer des données vers et depuis un réseau. Entrez la commande pour faire une requête HTTP GET à notre serveur en cours d’exécution :

      • curl http://localhost:8000

      Lorsque nous appuyons sur ENTER, notre terminal affichera la sortie suivante :

      Output

      My first server!

      Nous avons maintenant mis en place un serveur et nous avons obtenu notre première réponse du serveur.

      Décomposons ce qui s’est passé lorsque nous avons testé notre serveur. En utilisant cURL, nous avons envoyé une requête GET au serveur sur http://localhost:8000. Notre serveur Node.js a écouté les connexions à partir de cette adresse.  Le serveur a transmis cette requête à la fonction requestListener(). Cette fonction a renvoyé des données textuelles avec le code d’état 200. Le serveur a alors renvoyé cette réponse à cURL, qui a affiché le message dans notre terminal.

      Avant de continuer, quittons notre serveur en cours d’exécution en appuyant sur CTRL+C. Cela interrompt l’exécution de notre serveur, nous renvoyant à l’invite de la ligne de commande.

      Dans la plupart des sites web que nous visit ou API nous utilisons, les réponses du serveur sont rarement en texte en clair. Nous obtenons des pages HTML et des données JSON comme formats de réponse courants. Dans la prochaine étape, nous apprendrons comment renvoyer des réponses HTTP dans les formats de données courants que nous rencontrons sur le web.

      Étape 2 – Renvoi de différents types de contenu

      La réponse que nous recevons d’un serveur web peut prendre plusieurs formats. JSON et HTML ont déjà été mentionnés, et nous pouvons également renvoyer d’autres formats de texte comme XML et CSV. Enfin, les serveurs web peuvent renvoyer des données non textuelles telles que des PDF, des fichiers zippés, des fichiers audio et vidéo.

      Dans cet article, en plus du texte clair que nous venons de renvoyer, vous apprendrez comment renvoyer les types de données suivants :

      Les trois types de données sont tous basés sur le texte et sont des formats populaires pour la diffusion de contenu sur le web. De nombreux outils et langages de développement côté serveur prennent en charge le retour de ces différents types de données. Dans le contexte de Node.js, nous devons faire deux choses :

      1. Définir l’en-tête Content-Type dans nos réponses HTTP avec la valeur appropriée.
      2. Nous assurert que res.end() reçoit les données au bon format.

      Voyons cela en action avec quelques exemples. Le code que nous allons écrire dans cette section et les suivantes présentent de nombreuses similitudes avec le code que nous avons écrit précédemment. La plupart des modifications existent dans la fonction requestListener(). Créons des fichiers avec ce “code modèle” afin de rendre les futures sections plus faciles à suivre.

      Créez un nouveau fichier appelé html.js : Ce fichier sera utilisé plus tard pour renvoyer du texte HTML dans une réponse HTTP. Nous allons mettre le code modèle ici et le copier aux autres serveurs qui renvoient différents types.

      Dans le terminal, entrez ce qui suit :

      Ouvrez maintenant ce fichier dans un éditeur de texte :

      Copions le “code modèle”. Saisissez ceci dans 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}`);
      });
      

      Enregistrez et quittez html.js avec CTRL+X, puis retournez au terminal.

      Maintenant, copions ce fichier dans deux nouveaux fichiers. Le premier fichier servira à renvoyer les données CSV dans la réponse HTTP :

      Le second fichier retournera une réponse JSON dans le serveur :

      Les autres fichiers seront destinés à des exercices ultérieurs :

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

      Nous sommes maintenant prêts pour continuer nos exercices. Commençons par retourner JSON.

      Servir JSON

      JavaScript Object Notation, communément appelée JSON, est un format d’échange de données basé sur le texte. Comme son nom l’indique, il est dérivé d’objets JavaScript, mais il est indépendant du langage, ce qui signifie qu’il peut être utilisé par tout langage de programmation capable d’analyser sa syntaxe.

      JSON est couramment utilisé par les API pour accepter et renvoyer des données. Sa popularité est due à une taille de transfert de données inférieure aux normes d’échange de données précédentes comme XML, ainsi qu’à l’outillage existant qui permet aux programmes de les analyser sans effort excessif. Si vous souhaitez en savoir plus sur JSON, vous pouvez lire notre guide Comment travailler avec JSON en JavaScript.

      Ouvrez le fichier json.js avec nano :

      Nous voulons renvoyer une réponse JSON. Modifions la fonction requestListener() pour renvoyer l’en-tête approprié de toutes les réponses JSON en changeant les lignes surlignées comme ceci :

      first-servers/json.js

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

      La méthode res.setHeader() ajoute un en-tête HTTP à la réponse. Les en-têtes HTTP sont des informations supplémentaires qui peuvent être jointes à une requête ou à une réponse. La méthode res.setHeader() prend deux arguments : le nom de l’en-tête et sa valeur.

      L’en-tête Content-Type est utilisé pour indiquer le format des données, également appelé media type, qui sont envoyées avec la requête ou la réponse.  Dans ce cas, notre Content-Type est application/json.

      Maintenant, retournons le contenu JSON à l’utilisateur. Modifiez json.js pour qu’il ressemble à ceci :

      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"}`);
      };
      ...
      

      Comme précédemment, nous indiquons à l’utilisateur que sa demande a abouti en lui renvoyant un code de statut 200. Cette fois-ci, dans l’appel response.end(), notre argument chaîne de caractères contient un JSON valide.

      Enregistrez et quittez json.js en appuyant sur CTRL+X. Maintenant, lançons le serveur avec la commande node :

      Dans un autre terminal, atteignons le serveur en utilisant cURL :

      • curl http://localhost:8000

      En appuyant sur ENTER, nous obtiendrons le résultat suivant :

      Output

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

      Nous avons maintenant renvoyé avec succès une réponse JSON, tout comme beaucoup d’API populaires avec lesquelles nous créons des applications. Veillez à quitter le serveur en cours d’exécution avec CTRL+C afin que nous puissions retourner à l’invite du terminal standard. Ensuite, examinons un autre format populaire de retour de données : CSV.

      Servir CSV

      Le format de fichier CSV (Comma Separated Values) est une norme de texte couramment utilisée pour fournir des données tabulaires. Dans la plupart des cas, chaque ligne est séparée par une nouvelle ligne, et chaque élément de la ligne est séparé par une virgule.

      Dans notre espace de travail, ouvrons le fichier csv.js avec un éditeur de texte :

      Ajoutons les lignes suivantes à notre fonction requestListener() :

      first-servers/csv.js

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

      Cette fois, notre Content-Type indique qu’un fichier CSV est renvoyé car la valeur est text/csv. Le deuxième en-tête que nous ajoutons est Content-Disposition. Cet en-tête indique au navigateur comment afficher les données, en particulier dans le navigateur ou en tant que fichier séparé.

      Lorsque nous renvoyons des réponses CSV, la plupart des navigateurs modernes téléchargent automatiquement le fichier même si l’en-tête Content-Disposition n’est pas défini. Cependant, lorsque nous renvoyons un fichier CSV, nous devons quand même ajouter cet en-tête car il nous permet de définir le nom du fichier CSV. Dans ce cas, nous signalons au navigateur que ce fichier CSV est une pièce jointe et qu’il doit être téléchargé. Nous indiquons ensuite au navigateur que le nom du fichier est oceanpals.csv.

      Écrivons les données CSV dans la réponse 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,emailn1,Sammy Shark,shark@ocean.com`);
      };
      ...
      

      Comme avant, nous retournons un statut 200/OK avec notre réponse. Cette fois, notre appel à res.end() contient une chaîne de caractères qui est un CSV valide. La virgule sépare la valeur dans chaque colonne et le nouveau caractère de ligne (n) sépare les lignes. Nous avons deux lignes, l’une pour l’en-tête de la table et l’autre pour les données.

      Nous allons tester ce serveur dans le navigateur. Enregistrez csv.js et quittez l’éditeur avec CTRL+X.

      Lancez le serveur avec la commande Node.js :

      Dans un autre Terminal, rejoignons le serveur en utilisant cURL :

      • curl http://localhost:8000

      La console affichera ceci :

      Output

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

      Si nous allons sur http://localhost:8000 dans notre navigateur, un fichier CSV sera téléchargé.  Son nom de fichier sera oceanpals.csv.

      Quittez le serveur en cours d’exécution avec CTRL+C pour revenir à l’invite standard du terminal.

      Après avoir renvoyé JSON et CSV, nous avons couvert deux cas populaires pour les API. Passons maintenant à la manière dont nous renvoyons les données pour les sites web que les gens consultent dans un navigateur.

      Servir HTML

      HTML, HyperText Markup Language, est le format le plus courant à utiliser lorsque nous voulons que des utilisateurs interagissent avec notre serveur via un navigateur web. Il a été créé pour structurer le contenu web. Les navigateurs web sont conçus pour afficher du contenu HTML, ainsi que tous les styles que nous ajoutons avec le CSS, une autre technologie web front-end qui nous permet de modifier l’esthétique de nos sites web.

      Réouvrons html.js avec notre éditeur de texte :

      Modifiez la fonction requestListener() pour renvoyer l’en-tête Content-Type approprié pour une réponse HTML :

      first-servers/html.js

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

      Maintenant, retournons le contenu HTML à l’utilisateur. Ajoutez les lignes surlignées au fichier html.js pour qu’il ressemble à ceci :

      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>`);
      };
      ...
      

      Nous ajoutons d’abord le code de statut HTTP. Nous appelons ensuite response.end() avec un argument de chaîne contenant du HTML valide. Lorsque nous accédons à notre serveur dans le navigateur, nous verrons une page HTML avec une balise d’en-tête contenant This is HTML.

      Enregistrez et quittez en appuyant sur CTRL+X. Maintenant, lançons le serveur avec la commande node :

      Nous verrons Server is running on http://localhost:8000 lorsque notre programme a démarré.

      Maintenant, allez dans le navigateur et visitez http://localhost:8000. Notre page ressemblera à ceci :

      Image de la réponse HTML renvoyée par le serveur Node.js

      Quittons le serveur en cours d’exécution avec CTRL+C et revenons à l’invite standard du terminal.

      Il est courant que le HTML soit écrit dans un fichier, séparé du code côté serveur comme nos programmes Node.js. Voyons ensuite comment nous pouvons renvoyer des réponses HTML à partir de fichiers.

      Étape 3 – Servir une page HTML à partir d’un fichier

      Nous pouvons servir le HTML comme des chaînes dans Node.js à l’utilisateur, mais il est préférable que nous chargeions les fichiers HTML et que nous servions leur contenu. De cette façon, lorsque le fichier HTML se développe, nous n’avons pas à maintenir de longues chaînes dans notre code Node.js, ce qui le rend plus concis et nous permet de travailler sur chaque aspect de notre site web de manière indépendante. Cette “séparation des préoccupations” est courante dans de nombreuses configurations de développement web, il est donc bon de savoir comment charger les fichiers HTML pour les prendre en charge dans Node.js

      Pour servir les fichiers HTML, nous chargeons le fichier HTML avec le module fs et utilisons ses données lors de l’écriture de notre réponse HTTP.

      Tout d’abord, nous créons un fichier HTML que le serveur web renvoie. Créez un nouveau fichier HTML :

      Maintenant, ouvrez index.html dans un éditeur de texte :

      Notre page web sera minimale. Elle aura un fond orange et affichera un texte de salutation au centre. Ajoutez ce code au fichier :

      first-servers/index.html

      <!DOCTYPE html>
      
      <head>
          <title>My Website</title>
          <style>
              *,
              html {
                  margin: 0;
                  padding: 0;
                  border: 0;
              }
      
              html {
                  width: 100%;
                  height: 100%;
              }
      
              body {
                  width: 100%;
                  height: 100%;
                  position: relative;
                  background-color: rgb(236, 152, 42);
              }
      
              .center {
                  width: 100%;
                  height: 50%;
                  margin: 0;
                  position: absolute;
                  top: 50%;
                  left: 50%;
                  transform: translate(-50%, -50%);
                  color: white;
                  font-family: "Trebuchet MS", Helvetica, sans-serif;
                  text-align: center;
              }
      
              h1 {
                  font-size: 144px;
              }
      
              p {
                  font-size: 64px;
              }
          </style>
      </head>
      
      <body>
          <div class="center">
              <h1>Hello Again!</h1>
              <p>This is served from a file</p>
          </div>
      </body>
      
      </html>
      

      Cette page web unique affiche deux lignes de texte :Hello again! et This is served from a file. Les lignes apparaissent au centre de la page, l’une au-dessus de l’autre. La première ligne de texte est affichée dans un titre, ce qui signifie qu’elle serait grande. La deuxième ligne de texte apparaîtra un peu plus petite. Tout le texte apparaîtra en blanc et la page web aura un fond orange.

      Bien que ce ne soit pas l’objet de cet article ou de cette série, si vous souhaitez en savoir plus sur le HTML, le CSS et d’autres technologies web frontales, vous pouvez consulter le guide de Mozilla intitulé Premiers pas avec le web.

      C’est tout ce dont nous avons besoin pour le HTML, alors enregistrez et quittez le fichier avec CTRL+X. Nous pouvons maintenant passer au code du serveur.

      Pour cet exercice, nous travaillerons sur htmlFile.js. Ouvrez-le avec l’éditeur de texte :

      Comme nous devons lire un fichier, commençons par importer le module fs :

      first-servers/htmlFile.js

      const http = require("http");
      const fs = require('fs').promises;
      ...
      

      Ce module contient une fonction readFile() que nous utiliserons pour charger le fichier HTML en place. Nous importons la variante promise en respectant les meilleures pratiques modernes de JavaScript. Nous utilisons les promesses en tant que syntaxe plus succincte que les rappels, que nous devrions utiliser si nous assignions fs à juste require('fs'). Pour en savoir plus sur les meilleures pratiques de programmation asynchrone, vous pouvez lire notre guide Comment écrire du code asynchrone dans Node.js.

      Nous voulons que notre fichier HTML soit lu lorsqu’un utilisateur sollicite notre système. Commençons par modifier requestListener() pour lire le fichier :

      first-servers/htmlFile.js

      ...
      const requestListener = function (req, res) {
          fs.readFile(__dirname + "/index.html")
      };
      ...
      

      Nous utilisons la méthode fs.readFile() pour charger le fichier. Son argument a __dirname + "/index.html". La variable spéciale __dirname a le chemin absolu de l’emplacement où le code Node.js est en cours d’exécution. Nous ajoutons ensuite /index.html afin de pouvoir charger le fichier HTML que nous avons créé précédemment.

      Maintenant, retournons la page HTML une fois qu’elle est chargée :

      first-servers/htmlFile.js

      ...
      const requestListener = function (req, res) {
          fs.readFile(__dirname + "/index.html")
              .then(contents => {
                  res.setHeader("Content-Type", "text/html");
                  res.writeHead(200);
                  res.end(contents);
              })
      };
      ...
      

      Si la promesse fs.readFile() se résout avec succès, elle renverra ses données. Nous utilisons la méthode then() pour traiter ce cas. Le paramètre contents contient les données du fichier HTML.

      Nous définissons d’abord l’en-tête Content-Type sur text/html pour indiquer au client que nous renvoyons les données HTML. Nous écrivons ensuite le code d’état pour indiquer que la demande a abouti. Nous envoyons enfin au client la page HTML que nous avons chargée avec les données dans la variable contents.

      La méthode fs.readFile() peut parfois échouer, c’est pourquoi nous devons gérer ce cas lorsque nous obtenons une erreur. Ajoutez ceci à la fonction requestListener() :

      first-servers/htmlFile.js

      ...
      const requestListener = function (req, res) {
          fs.readFile(__dirname + "/index.html")
              .then(contents => {
                  res.setHeader("Content-Type", "text/html");
                  res.writeHead(200);
                  res.end(contents);
              })
              .catch(err => {
                  res.writeHead(500);
                  res.end(err);
                  return;
              });
      };
      ...
      

      Sauvegardez le fichier et quittez nano avec CTRL+X.

      Lorsqu’une promesse rencontre une erreur, elle est rejetée. Nous traiterons ce cas avec la méthode catch(). Elle accepte l’erreur que fs.readFile() renvoie, met le code de statut à 500 signifiant qu’une erreur interne a été rencontrée, et renvoie l’erreur à l’utilisateur.

      Exécutez notre serveur avec la commande node :

      Dans le navigateur web, visitez http://localhost:8000. Vous verrez cette page :

      Image de la page HTML chargée à partir d'un fichier dans Node.js

      Vous avez maintenant renvoyé une page HTML du serveur à l’utilisateur. Vous pouvez quitter le serveur en cours d’exécution avec CTRL+C. Vous verrez le retour de l’invite du terminal lorsque vous le ferez.

      Lorsque vous écrivez un code de ce type en production, vous ne voudrez peut-être pas charger une page HTML chaque fois que vous recevez une requête HTTP. Alors que cette page HTML a une taille d’environ 800 octets, les sites web plus complexes peuvent avoir une taille de plusieurs mégaoctets. Le chargement de fichiers volumineux peut prendre un certain temps. Si votre site s’attend à un trafic important, il peut être préférable de charger les fichiers HTML au démarrage et de sauvegarder leur contenu. Une fois qu’ils sont chargés, vous pouvez configurer le serveur et lui faire écouter les requêtes sur une adresse.

      Pour démontrer cette méthode, voyons comment nous pouvons retravailler notre serveur pour qu’il soit plus efficace et plus évolutif.

      Servir efficacement le HTML

      Au lieu de charger le HTML pour chaque requête, dans cette étape, nous le chargerons une fois, au début. La requête renverra les données que nous avons chargées au démarrage.

      Dans le terminal, réouvrez le script Node.js avec un éditeur de texte :

      Commençons par ajouter une nouvelle variable avant de créer la fonction requestListener() :

      first-servers/htmlFile.js

      ...
      let indexFile;
      
      const requestListener = function (req, res) {
      ...
      

      Lorsque nous exécutons ce programme, cette variable contiendra le contenu du fichier HTML.

      Maintenant, réajustons la fonction requestListener(). Au lieu de charger le fichier, il va maintenant renvoyer le contenu de indexFile :

      first-servers/htmlFile.js

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

      Ensuite, nous déplaçons la logique de lecture du fichier de la fonction requestListener() au démarrage de notre serveur. Effectuez les changements suivants au moment de la création du serveur :

      first-servers/htmlFile.js

      ...
      
      const server = http.createServer(requestListener);
      
      fs.readFile(__dirname + "/index.html")
          .then(contents => {
              indexFile = contents;
              server.listen(port, host, () => {
                  console.log(`Server is running on http://${host}:${port}`);
              });
          })
          .catch(err => {
              console.error(`Could not read index.html file: ${err}`);
              process.exit(1);
          });
      

      Sauvegardez le fichier et quittez nano avec CTRL+X.

      Le code qui lit le fichier est semblable à celui que nous avons écrit lors de notre première tentative. Cependant, lorsque nous réussissons à lire le fichier, nous enregistrons maintenant le contenu dans notre variable globale indexFile. Nous démarrons ensuite le serveur avec la méthode listen() L’essentiel est que le fichier soit chargé avant que le serveur ne soit lancé. De cette façon, la fonction requestListener() sera sûre de renvoyer une page HTML, car indexFile n’est plus une variable vide.

      Notre gestionnaire d’erreurs a également changé. Si le fichier ne peut pas être chargé, nous récupérons l’erreur et l’imprimons sur notre console. Nous quittons ensuite le programme Node.js avec la fonction exit() sans démarrer le serveur. De cette façon, nous pouvons voir pourquoi la lecture du fichier a échoué, résoudre le problème, puis redémarrer le serveur.

      Nous avons maintenant créé différents serveurs web qui renvoient différents types de données à un utilisateur. Jusqu’à présent, nous n’avons utilisé aucune donnée de requête pour déterminer ce qui doit être renvoyé. Nous devrons utiliser des données de requête lors de la configuration de routes ou de chemins différents dans un serveur Node.js, alors voyons maintenant comment ils fonctionnent ensemble.

      Étape 4 – Gestion des routes à l’aide d’un Objet de requête HTTP

      La plupart des sites web que nous visitons ou des API que nous utilisons ont généralement plus d’un point d’accès, ce qui nous permet d’accéder à diverses ressources. Un bon exemple serait un système de gestion des livres, qui pourrait être utilisé dans une bibliothèque. Il ne devrait pas seulement gérer les données relatives aux livres, mais aussi les données relatives aux auteurs pour faciliter le catalogage et la recherche.

      Même si les données concernant les livres et les auteurs sont liées, il s’agit de deux objets différents. Dans ce cas, les développeurs de logiciels codent généralement chaque objet sur des terminaux différents afin d’indiquer à l’utilisateur de l’API le type de données avec lesquelles ils interagissent.

      Créons un nouveau serveur pour une petite bibliothèque, qui renverra deux types de données différents. Si l’utilisateur se rend à l’adresse de notre serveur à /books, il recevra une liste de livres en JSON. S’il se rend à l’adresse /authors, il recevra une liste d’informations sur les auteurs en JSON.

      Jusqu’à présent, nous avons répondu de la même manière à toutes les demandes que nous avons reçues. Illustrons cela rapidement.

      Relancez notre exemple de réponse JSON :

      Dans un autre terminal, faisons une demande CURL comme précédemment :

      • curl http://localhost:8000

      Vous verrez :

      Output

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

      Maintenant, essayons une autre commande curl :

      • curl http://localhost:8000/todos

      Après avoir appuyé sur Enter, vous verrez le même résultat :

      Output

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

      Nous n’avons pas intégré de logique spéciale dans notre fonction requestListener() pour traiter une requête dont l’URL contient /todos, donc Node.js retourne le même message JSON par défaut.

      Comme nous voulons construire un serveur de gestion de bibliothèque miniature, nous allons maintenant séparer le type de données qui sont retournées en fonction du point final auquel l’utilisateur accède.

      Tout d’abord, quittez le serveur en cours d’exécution avec CTRL+C.

      Maintenant, ouvrez routes.js dans votre éditeur de texte :

      Commençons par stocker nos données JSON dans des variables avant la fonction requestListener() :

      first-servers/routes.js

      ...
      const books = JSON.stringify([
          { title: "The Alchemist", author: "Paulo Coelho", year: 1988 },
          { title: "The Prophet", author: "Kahlil Gibran", year: 1923 }
      ]);
      
      const authors = JSON.stringify([
          { name: "Paulo Coelho", countryOfBirth: "Brazil", yearOfBirth: 1947 },
          { name: "Kahlil Gibran", countryOfBirth: "Lebanon", yearOfBirth: 1883 }
      ]);
      ...
      

      La variable livres est une chaîne qui contient JSON pour un tableau d’objets livres. Chaque livre a un titre ou un nom, un auteur, et l’année de sa publication.

      La variable authors est une chaîne de caractères qui contient le JSON pour un tableau d’objets auteur. Chaque auteur a un nom, un pays de naissance et une année de naissance.

      Maintenant que nous avons les données que nos réponses vont renvoyer, commençons à modifier la fonction requestListener() pour les renvoyer vers les chemins corrects.

      Tout d’abord, nous allons nous assurer que chaque réponse de notre serveur a l’en-tête Content-Type correct :

      first-servers/routes.js

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

      Maintenant, nous voulons renvoyer le bon JSON en fonction du chemin URL utilisé par l’utilisateur. Créons une déclaration switch sur l’URL de la requête :

      first-servers/routes.js

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

      Pour obtenir le chemin de l’URL d’un objet de requête, nous devons accéder à la propriété de son url. Nous pouvons maintenant ajouter des cas à la déclaration switch pour renvoyer le JSON approprié.

      L’instruction switch de JavaScript permet de contrôler le code qui est exécuté en fonction de la valeur d’un objet ou d’une expression JavaScript (par exemple, le résultat d’opérations mathématiques). Si vous avez besoin d’une leçon ou d’un rappel sur la manière de les utiliser, consultez notre guide Comment utiliser la déclaration switch en JavaScript.

      Continuons en ajoutant un cas pour lequel l’utilisateur veut obtenir notre liste de livres :

      first-servers/routes.js

      ...
      const requestListener = function (req, res) {
          res.setHeader("Content-Type", "application/json");
          switch (req.url) {
              case "/books":
                  res.writeHead(200);
                  res.end(books);
                  break
          }
      }
      ...
      

      Nous fixons notre code de statut à 200 pour indiquer que la demande est correcte et nous renvoyons le JSON contenant la liste de nos livres. Maintenant, ajoutons un autre cas pour nos auteurs :

      first-servers/routes.js

      ...
      const requestListener = function (req, res) {
          res.setHeader("Content-Type", "application/json");
          switch (req.url) {
              case "/books":
                  res.writeHead(200);
                  res.end(books);
                  break
              case "/authors":
                  res.writeHead(200);
                  res.end(authors);
                  break
          }
      }
      ...
      

      Comme précédemment, le code de statut sera 200 car la requête est bonne. Cette fois, nous retournons le JSON contenant la liste de nos auteurs.

      Nous voulons renvoyer une erreur si l’utilisateur essaie d’aller par un autre chemin. Ajoutons le cas par défaut pour ce faire :

      routes.js

      ...
      const requestListener = function (req, res) {
          res.setHeader("Content-Type", "application/json");
          switch (req.url) {
              case "/books":
                  res.writeHead(200);
                  res.end(books);
                  break
              case "/authors":
                  res.writeHead(200);
                  res.end(authors);
                  break
              default:
                  res.writeHead(404);
                  res.end(JSON.stringify({error:"Resource not found"}));
          }
      }
      ...
      

      Nous utilisons le mot-clé default dans une déclaration switch pour capturer tous les autres scénarios non capturés par nos cas précédents. Nous fixons le code de statut à 404 pour indiquer que l’URL qu’il recherchait n’a pas été trouvée. Nous définissons ensuite un objet JSON qui contient un message d’erreur.

      Testons notre serveur pour voir s’il se comporte comme nous l’attendons. Dans un autre terminal, lançons d’abord une commande pour voir si nous récupérons notre liste de livres :

      • curl http://localhost:8000/books

      Appuyez sur Enter pour voir la sortie suivante :

      Output

      [{"title":"The Alchemist","author":"Paulo Coelho","year":1988},{"title":"The Prophet","author":"Kahlil Gibran","year":1923}]

      Jusqu’à présent, tout va bien. Essayons la même chose pour /authors. Tapez la commande suivante dans le terminal :

      • curl http://localhost:8000/authors

      Vous verrez la sortie suivante lorsque la commande sera terminée :

      Output

      [{"name":"Paulo Coelho","countryOfBirth":"Brazil","yearOfBirth":1947},{"name":"Kahlil Gibran","countryOfBirth":"Lebanon","yearOfBirth":1883}]

      Enfin, essayons une URL erronée pour nous assurer que requestListener() renvoie la réponse d’erreur :

      • curl http://localhost:8000/notreal

      La saisie de cette commande affichera ce message :

      Output

      {"error":"Resource not found"}

      Vous pouvez quitter le serveur en cours d’exécution avec CTRL+C.

      Nous avons maintenant créé différentes possibilités pour que les utilisateurs puissent obtenir des données différentes. Nous avons également ajouté une réponse par défaut qui renvoie une erreur HTTP si l’utilisateur entre une URL que nous ne prenons pas en charge.

      Conclusion

      Dans ce tutoriel, vous avez réalisé une série de serveurs HTTP Node.js. Vous avez d’abord renvoyé une réponse textuelle de base. Vous avez ensuite demandé de renvoyer différents types de données de notre serveur : JSON, CSV et HTML. À partir de là, vous avez pu combiner le chargement de fichiers avec les réponses HTTP pour renvoyer une page HTML du serveur à l’utilisateur, et créer une API qui utilisait les informations relatives à la requête de l’utilisateur pour déterminer quelles données devaient être envoyées dans sa réponse.

      Vous êtes maintenant équipé pour créer des serveurs web qui peuvent traiter une variété de requêtes et de réponses. Grâce à ces connaissances, vous pouvez créer un serveur qui renvoie de nombreuses pages HTML à l’utilisateur à différents endroits. Vous pouvez également créer votre propre API.

      Pour en savoir plus sur les serveurs web HTTP dans Node.js, vous pouvez lire la documentation de Node.js sur le module http. Si vous souhaitez poursuivre l’apprentissage de Node.js, vous pouvez retourner à la page de la série Comment coder en Node.js.



      Source link