Перейти до основного вмісту

Web сервер на Node.js

Тепер ми створимо найпростіший web-сервер, для відображення статичного сайту. Структура сайту буде наступною:

Рис. 3 - структура статичного веб-сайта

Файл index.html містить наступну розмітку:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="/css/main.css" />
<title>Simple site</title>
</head>
<body>
<h3>Приклад простого сайту</h3>
<img
src="/img/photo.jpg"
alt="photo of turned on laptop computer"
class="picture"
/>
<div class="js-class"></div>
<script src="/js/main.js"></script>
</body>
</html>

У ньому ми підключаємо стилі з файлу main.css та javascript код із файлу main.js . Також у нас у html відображається картинка. Це зроблено для того, щоб наш сервер віддавав будь-який файл, який запросить у нього браузер, стилі, код або зображення. Щоб перевірити, що 'main.js' підключився правильно, ми виводимо відповідне повідомлення у index.html

const container = document.querySelector('.js-class');
container.textContent = 'javaScript підключений на сторінці';

Створимо файл server.js і помістимо в нього наступний код, щоб наш сайт правильно відображався під час запуску:

const http = require('docs/additional_materials/simple-web-server/http');
const fs = require('fs').promises;
const url = require('url');
const path = require('path');

const contentType = {
'.html': 'text/html',
'.js': 'text/javascript',
'.css': 'text/css',
'.jpg': 'image/jpeg',
'.ico': 'image/x-icon',
};

http
.createServer(async (req, res) => {
const { pathname } = url.parse(req.url);
let filename = pathname.substring(1);
if (pathname === '/') {
filename = 'index.html';
}
const type = contentType[path.extname(filename)];
res.writeHead(200, { 'Content-Type': type });
if (type.includes('image')) {
const img = await fs.readFile(filename);
res.write(img, 'hex');
} else {
const content = await fs.readFile(filename, 'utf8');
res.write(content);
}
res.end();
})
.listen(3000, () => console.log('Listen server on port 3000'));

Виконаємо наш код наступною командою:

$ node server.js

Після виконання ми побачимо повідомлення - Listen server on port 3000 Це означає, що сервер запущений та готовий до роботи. Відкриємо браузер та перейдемо за адресою http://localhost:3000/ ми побачимо наступне вікно

alt text

Мал. 4 - реалізація простого http сервера

Ми бачимо, що заголовок синього кольору, а значить, стилі підключилися, також бачимо повідомлення з main.js . Давайте докладніше розберемо код і що тут відбувається. Спочатку ми підключаємо модулі, які необхідні для роботи. Далі ми бачимо об'єкт з MIME типами, який дозволить нам віддавати різноманітний контент: Що це означає? Заголовок-сутність Content-Type при відповіді браузеру використовується щоб визначити MIME тип ресурсу. У відповідях сервера заголовок Content-Type повідомляє клієнту, який буде тип контенту, що передається. В деяких випадках браузери намагаються самі визначити MIME тип переданого контенту, але їхня реакція може бути неадекватною. Тому коли ми віддаватимемо файл клієнту, ми знаючи, розширення файлу, можемо підставляти відповідний MIME тип у заголовок Content-Type

const contentType = {
'.html': 'text/html',
'.js': 'text/javascript',
'.css': 'text/css',
'.jpg': 'image/jpeg',
'.ico': 'image/x-icon',
};

Модуль path, який відповідає за різні операції із шляхами файлів. Бо в GET запити параметри передаються через url , для їх обробки ми повинні проаналізувати цей рядок. Це зручно зробити за допомогою стандартного модуля url та його функції parse

const { pathname } = url.parse(req.url);

Далі знаходимо ім'я файлу, який запросив клієнт через HTTP-запит

let filename = pathname.substring(1);

Тут ми відкидаємо знак ‘/’ з якого розпочинається шлях до файлу. Єдиним винятком є ​​звернення до кореня сайту, і тоді необхідно віддавати файл index.html

if (pathname === '/') {
filename = 'index.html';
}

Визначаємо розширення файлу, на який надійшов запит від клієнта та вибираємо необхідний MIME тип змінної type. І встановлюємо заголовок відповіді Content-Type

const type = contentType[path.extname(filename)];
res.writeHead(200, { 'Content-Type': type });

Оскільки віддача зображень та текстових файлів відрізняється, ми перевіряємо, чи не чи надійшов запит на картинку від клієнта. І оскільки зображення – це двійкові файли, то ми зчитуємо файл і передаємо лічений буфер метод write , де другим параметром встановлюємо кодування 'hex'.

if (type.includes('image')) {
const img = await fs.readFile(filename);
res.write(img, 'hex');
} else {
const content = await fs.readFile(filename, 'utf8');
res.write(content);
}
res.end();

Якщо це текстовий файл, то при зчитуванні файлу вказуємо кодування utf8. Закінчуємо відповідь на запит командою res.end()

Ми розглянули мінімально можливий веб-сервер. Але для обслуговування веб-сайтів використовують фреймворки, такі як Express, які беруть на себе роботу з побудові веб-сервера з нуля.