Как создать сервер на node js
Перейти к содержимому

Как создать сервер на node js

  • автор:

Node.JS для решения задач

Материал на этой странице устарел, поэтому скрыт из оглавления сайта.

В этом разделе предлагаются задачи по теме AJAX.

Конечно же, они требуют взаимодействия с сервером. Мы будем использовать серверную часть, написанную на JavaScript, на Node.JS.

Если вы не использовали Node.JS ранее – не беспокойтесь. Здесь нашей целью является преимущественно клиентская часть, поэтому прямо сейчас изучать Node.JS не обязательно. Серверные скрипты уже готовы. Нужно только поставить Node.JS и модули, чтобы их запускать.

Установка

Для настройки окружения будет достаточно сделать два шага:

  1. Сначала установите сам сервер Node.JS. Если у вас Unix-система – рекомендуется собрать последнюю версию из исходников, а также NPM. Вы справитесь. Если Windows – посетите сайт https://nodejs.org или скачайте установщик (32 или 64-битный) с расширением .msi из https://nodejs.org/dist/latest/.
  2. Выберите директорию, в которой будете решать задачи. Запустите в ней:

npm install node-static

Проверка

    Создайте какую-нибудь поддиректорию и в ней файл server.js с таким содержимым:

var http = require('http'); var static = require('node-static'); var file = new static.Server('.'); http.createServer(function(req, res) < file.serve(req, res); >).listen(8080); console.log('Server running on port 8080');
Server running on port 8080

Нельзя запустить больше одного сервера одновременно!

При попытке запуска двух серверов (например, в разных консолях) – будет конфликт портов и ошибка.

  1. Откройте в браузере http://127.0.0.1:8080/server.js. Должно вывести код файла server.js .

Если всё работает – отлично, теперь вы готовы решать задачи.

Примеры

В примерах, за редким исключением, для краткости будет приводиться не полный скрипт на Node.JS, а только код обработки запроса.

var http = require('http'); var url = require('url'); var querystring = require('querystring'); function accept(req, res) < res.writeHead(200, < 'Content-Type': 'text/plain', 'Cache-Control': 'no-cache' >); res.end("OK"); > http.createServer(accept).listen(8080);

…Будет только функция accept , или даже только её содержимое:

res.writeHead(200, < 'Content-Type': 'text/plain', 'Cache-Control': 'no-cache' >);

Основные методы

В функции accept используются два объекта:

  • req – объект запроса («request»), то есть то, что прислал клиент (обычно браузер), из него читаем данные.
  • res – объект ответа («response»), в него пишем данные в ответ клиенту.
    • вызов res.writeHead(HTTP-код, [строка статуса], ) пишет заголовки.
    • вызов res.write(txt) пишет текст в ответ.
    • вызов res.end(txt) – завершает запрос ответом.

    Демо

    Кроме просмотра кода, можно будет попробовать и скачать различные демки.

    Вот пример демо, можете попробовать нажать на кнопку – она работает.

    Если хотите посмотреть пример поближе и поиграть с ним – скачайте архив (кнопка справа-сверху в примере выше), он будет работать и на вашем Node.JS.

    Больше о Node.JS

    Больше о сервере Node.JS можно узнать в скринкасте по Node.JS.

    как запустить сервер node js

    Для запуска сервера Node.js нужно выполнить несколько шагов:

    1. Установить Node.js на компьютер, если он еще не установлен. Скачать установщик можно на официальном сайте Node.js.
    2. Создать файл с расширением .js , в котором будет содержаться код для запуска сервера. Например, создадим файл server.js .
    3. В файле server.js нужно написать код для создания сервера. Вот простой пример:
    const http = require('http'); const hostname = '127.0.0.1'; const port = 3000; const server = http.createServer((req, res) =>  res.statusCode = 200; res.setHeader('Content-Type', 'text/plain'); res.end('Hello, World!\n'); >); server.listen(port, hostname, () =>  console.log(`Server running at http://$hostname>:$port>/`); >); 

    Этот код создает сервер на локальном хосте (127.0.0.1) и порту 3000. Когда сервер запущен, он будет отвечать на любые запросы с сообщением «Hello, World!».

    1. Запустить сервер нужно в командной строке (терминале) из папки, где находится файл server.js . Например, если файл находится в папке myproject , то нужно перейти в эту папку командой cd myproject , а затем запустить сервер командой node server.js .
    2. Если все настроено правильно, то в консоли должно появиться сообщение «Server running at http://127.0.0.1:3000/ «, а в браузере можно открыть страницу по адресу http://127.0.0.1:3000/ и увидеть сообщение «Hello, World!».

    Создание простого веб-сервера с помощью Node.js и Express

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

    Создаваемый сервер будет обслуживать HTML-страницу, доступную другим людям. К концу статьи вы усвоите базовые знания о:

    • Node.js;
    • Express;
    • npm;
    • создании маршрутов Express;
    • обслуживании HTML;
    • настройке статических ресурсов Express.

    Совет: не копируйте код урока, а напишите его сами. Это позволит вам лучше его понять и усвоить.

    Создание и инициализация проекта

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

    mkdir express-server
    cd express-server

    После создания проекта нужно его инициализировать:

    npm init -y

    Эта команда создает файл package.json и инициализирует его с предустановленными значениями. Если вы захотите сами заполнить его поля, удалите флаг -y и следуйте инструкциям.

    Добавление Express

    После инициализации проекта Node.js мы переходим к следующему шагу — добавлению Express. Установка пакетов в Node.js выполняется командой npm install packageName .

    Для добавления последней стабильной версии Express выполните:

    npm install express

    После установки Express файл package.json будет выглядеть так:

     "name": "express-server", 
    "version": "1.0.0",
    "description": "",
    "main": "index.js",
    "scripts": "test": "echo \"Error: no test specified\" && exit 1"
    >,
    "keywords": [],
    "author": "",
    "license": "ISC",
    "dependencies": "express": "^4.17.1"
    >
    >

    Express перечислен среди dependencies , значит, он установился успешно. Переходим к третьему шагу — созданию сервера.

    Создание сервера Express

    Прежде чем продолжать, нужно создать для сервера JS-файл. Выполните в терминале следующую команду:

    touch index.js

    Теперь откройте этот файл и пропишите в нем:

    const express = require('express');
    const app = express();

    Что эти строки делают?

    1. Первая импортирует Express в проект, чтобы его можно было использовать. При каждом добавлении в проект пакета необходимо импортировать его туда, где он будет использоваться.
    2. Вторая строка вызывает функцию express , которая создает новое приложение, после чего присваивает результат константе app .

    Создание маршрутов и прослушивание порта

    Говоря простым языком, маршрут представляет конечную точку, к которой могут обращаться пользователи. Он ассоциируется с HTTP-глаголом (например, GET, POST и пр.) и получает путь URL. Кроме того, он получает функцию, которая вызывается при обращении к этой конечной точке.

    Пропишите в файле следующий код:

    app.get('/', (req, res) => res.send(< message: 'Hello WWW!' >);
    >);

    Разберем его согласно приведенной ранее структуре:

    • Он связан с HTTP-глаголом — в данном случае GET.
    • Он получает URL — здесь это домашняя страница ( / ).
    • Он получает функцию, которая будет вызываться при обращении к конечной точке.

    Следовательно, когда пользователь выполняет запрос GET к домашней странице, т.е. localhost:3333 , вызывается стрелочная функция и отображается фраза “Hello WWW!”

    Последним шагом подготовки сервера к работе будет настройка слушателя. Понадобится указать для приложения конкретный порт. Напишите нижеприведенный код в конец JS-файла.

    app.listen(3333, () => console.log('Application listening on port 3333!');
    >);

    Чтобы иметь возможность запускать сервер, вам нужно будет вызывать метод listen . При этом вы также можете изменить номер порта (3333) на любой другой.

    Доступ к приложению в браузере

    Для запуска приложения выполните в терминале node index.js . Имейте в виду, что index.js — это произвольное имя, которое я выбрал для данного урока, так что можете назвать его app.js или как-угодно иначе.

    Теперь, когда сервер запущен, можно обратиться к нему в браузере. Перейдите по адресу http://localhost:3333/ , перед вами должно отобразиться следующее сообщение:

    Вы отлично справились с настройкой веб-сервера Node.js + Express. В следующем разделе мы настроим статическое содержимое, а именно JavaScript, CSS, HTML, изображения и т.д.

    Статические файлы

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

    В этом разделе вы узнаете, как настраивать и передавать статические ресурсы, такие как HTML, JavaScript, CSS и изображения.

    Импорт модуля path

    Первым делом нужно импортировать в приложение модуль path . Устанавливать ничего не нужно, потому что path предустановлен в Node изначально.

    Пропишите в начале файла эту строку:

    const path = require('path');

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

    app.use(express.static(path.join(__dirname, 'public')));

    path.join получает два аргумента:

    • Текущую рабочую директорию (cwd).
    • Вторую директорию, которую нужно объединить с cwd.

    В качестве упражнения попробуйте вывести в консоль path.join(__dirname, ‘public’) и посмотрите, что получится.

    На данный момент сервер должен выглядеть так:

    const path = require('path');
    const express = require('express');
    const app = express();
    app.use(express.static(path.join(__dirname, 'public')))app.get('/', (req, res) => res.send(< message: 'Hello WWW!' >);
    >);
    app.listen(3333, () => console.log('Application listening on port 3333!');
    >);

    Создание каталога public и добавление ресурсов

    Создайте каталог и перейдите в него с помощью следующих команд:

    mkdir public
    cd public

    Теперь создадим пустые файлы, куда затем добавим HTML, CSS и JavaScript. Выполните в терминале следующие команды:

    touch app.js
    touch index.html
    touch styles.css

    Мы оставим app.js максимально простым, добавив только сообщение, подтверждающее, что он работает:

    alert('it works');

    То же и с styles.css . Для проверки его работоспособности мы установим цвет фона на синий:

    html background-color: blue;
    >

    В завершении нужно написать HTML, чтобы отображать все это на домашней странице. Откройте index.js и добавьте следующий HTML-код:








    My server


    My server


    Server built with Node.js and Express



    Теперь остается всего один шаг.

    Передача HTML-файла

    Мы почти закончили. Осталось только обработать HTML-код. Для этого нужно перейти в файл index.js и прописать в нем следующее:

    app.get('/', (req, res) => res.sendFile(`$/public/index.html`);
    >);

    Если вы уже ранее работали с Node.js и Express, то можете спросить: “Что здесь делает метод sendFile и почему мы не используем render ?” Метод render мы использовать не можем, так как не задействуем никакой движок (например, Pug, EJS и т.д.). Следовательно, когда кто-либо обращается к домашней странице, мы отправляем назад HTML-файл.

    Итоговый код сервера должен выглядеть так:

    const path = require('path');
    const express = require('express');
    const app = express();
    app.use(express.static(path.join(__dirname, 'public')))app.get('/', (req, res) => res.sendFile(`$/public/index.html`);
    >);
    app.listen(3333, () => console.log('Application listening on port 3333!');
    >);
    COPY

    Если теперь вы перейдете по http://localhost:3333 , то увидите домашнюю страницу с синим фоном. Естественно, сначала нужно будет закрыть надоедливое всплывающее окошко.

    Заключение

    К завершению статьи у вас должно получиться простое веб-приложение.

    В этом уроке мы узнали:

    • о Node.js;
    • об Express и о том, как использовать его для создания небольшого веб-приложения;
    • как создавать маршруты;
    • как настраивать статическое содержимое в приложении Node.js + Express;
    • как передавать простой HTML-файл в Express.
    • Создаем Telegram-бота с помощью Node.js за 3 минуты
    • Найти и обезвредить: утечки памяти в Node.js
    • Создание многопользовательской игры с использованием Socket.io при помощи NodeJS и React

    Свой веб-сервер на NodeJS, и ни единого фреймворка. Часть 1

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

    Новичку в NodeJS действительно может быть нелегко. JS — один из языков, в котором часто не существует единственного правильного решения конкретной задачи, а добавленные в ноду модули для работы с файловой системой, http сервером и прочими вещами, характерными для работы на сервере, затрудняют переход даже тем, кто пишет хороший код для браузеров. Тем не менее, я надеюсь, что вы знаете основы этого языка и его работы в серверном окружении, если нет, советую посмотреть замечательный скринкаст, который поможет разобраться в основах. И последнее — я не претендую на какой-то исключительно правильный код и буду рад услышать критику — мы все учимся, и это отличный способ получать знания.

    Начнём с файловой структуры

    Исходная папка nodejs хранится на сервере по пути /var/www/html/. В ней и будет наш веб-сервер. Дальше всё просто: создаём в ней директорию routing, в которой будет лежать наш скрипт index.js, а также 4 папки — dynamic, static, nopage и main — для динамически генерируемых страниц, статики, страницы 404 и главной страницы. Выглядит всё это так:

    nodejs
    —routing
    —-dynamic
    —-nopage
    —-static
    —-main
    —-index.js

    Создаём наш сервер

    Отлично, с файловой структурой более-менее определились. Теперь создаём в исходной папке файл server.js со следующим содержимым:

    // server.js // Для начала установим зависимости. const http = require('http'); const routing = require('./routing'); let server = new http.Server(function(req, res) < // API сервера будет принимать только POST-запросы и только JSON, так что записываем // всю нашу полученную информацию в переменную jsonString var jsonString = ''; res.setHeader('Content-Type', 'application/json'); req.on('data', (data) =>< // Пришла информация - записали. jsonString += data; >); req.on('end', () => ); >); server.listen(8000, 'localhost'); 

    Здорово! Теперь наш сервер будет принимать запросы, записывать JSON-данные, если они есть, но пока что будет вылетать с ошибкой, потому что у нас нет функции define в /routing/index.js. Время это исправить.

    // /routing/index.js const define = function(req, res, postData) < res.end('Hello, Habrahabr!'); >exports.define = define; 

    Запускаем наш сервер:

    node server.js

    Заходим туда, где он слушает запросы. Если вы не меняли код, это будет localhost:8000. Ура. Ответ есть.

    image

    Замечательно. Только это не совсем то, что нам нужно от сервера, правда?

    Ловим запросы к нашим API

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

    // /routing/index.js // Для начала установим зависимости. const url = require('url'); const fs = require('fs'); const define = function(req, res, postData) < // Теперь получаем наш адрес. Если мы переходим на localhost:3000/test, то path будет '/test' const urlParsed = url.parse(req.url, true); let path = urlParsed.pathname; // Теперь записываем полный путь к server.js. Мне это особенно нужно, так как сервер будет // висеть в systemd, и путь, о котором он будет думать, будет /etc/systemd/system/. prePath = __dirname; try < // Здесь мы пытаемся подключить модуль по ссылке. Если мы переходим на // localhost:8000/api, то скрипт идёт по пути /routing/dynamic/api, и, если находит там // index.js, берет его. Я знаю, что использовать тут try/catch не слишком правильно, и потом // переделаю через fs.readFile, но пока у вас не загруженный проект, разницу в скорости // вы не заметите. let dynPath = './dynamic/' + path; let routeDestination = require(dynPath); res.end('We have API!'); >catch (err) < // Не нашлось api? Грустно. res.end("We don't have API!"); >>; exports.define = define; 

    Готово. Теперь мы можем создать /routing/dynamic/api , и протестировать то, что у нас есть. Я воспользуюсь для этих целей своим готовым скриптом по адресу /dm/shortenUrl.

    image

    Определяем, есть ли страница

    Мы научились находить скрипты, теперь нужно научиться находить статику. Первым делом пойдём в /routing/nopage и создадим там index.html . Просто создайте костяк html-страницы, и сделайте один-единственный заголовок h1 с текстом: «404». После этого возвращаемся в /routing/index.js , но теперь мы сосредоточимся на уже написанном блоке catch:

    // /routing/index.js: блок catch catch (err) < // Находим наш путь к статическому файлу и пытаемся его прочитать. // Если вы не знаете, что это за '=>', тогда прочитайте про стрелочные функции в es6, // очень крутая штука. let filePath = prePath+'/static'+path+'/index.html'; fs.readFile(filePath, 'utf-8', (err, html) => < // Если не находим файл, пытаемся загрузить нашу страницу 404 и отдать её. // Если находим — отдаём, народ ликует и устраивает пир во имя царя-батюшки. if(err) < let nopath = '/var/www/html/nodejs/routing/nopage/index.html'; fs.readFile(nopath, (err , html) =>< if(!err) < res.writeHead(404, ); res.end(html); > // На всякий случай напишем что-то в этом духе, мало ли, иногда можно случайно // удалить что-нибудь и не заметить, но пользователи обязательно заметят. else< let text = "Something went wrong. Please contact webmaster@forgetable.ru"; res.writeHead(404, ); res.end(text); > >); > else< // Нашли файл, отдали, страница загружается. res.writeHead(200, ); res.end(html); > >); > 

    Воодушевляет. Теперь мы можем отдавать страницу 404, а так же html-страницы, которые мы добавляем сами в /routing/static . В моём случае страница 404 выглядит так:

    image

    Пара слов об API

    Способ организации скриптов — личное дело каждого. На данный момент код в блоке try у меня такой:

    let dynPath = './dynamic/' + path; let routeDestination = require(dynPath); routeDestination.promise(res,postData,req).then( result => < res.writeHead(200); res.end(result); return; >, error => < let endMessage = <>; endMessage.error = 1; endMessage.errorName = error; res.end(JSON.stringify(endMessage)); return; > ); 

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

    Обрабатываем запросы браузера

    Теперь мы уже можем пользоваться нашим сервером, и он будет возвращать страницы. Однако, если вы поместите в /routing/static/somepage ту же страницу, которая прекрасно работает, например, на апаче, вы столкнётесь с некоторыми проблемами.

    Во-первых, для этого веб-сервера, как и для, наверное, всех в таком роде, нужно иначе задавать ссылки на css/js/img/… файлы. Если вам хочется подключить к странице 404 css-файл и сделать её красивой, то в случае с апачем мы создали бы в той же папке nopage файл style.css и подключили бы его, указав в тэге link следующее: ‘href=«style.css»’. Однако, теперь нам нужно писать путь иначе, а именно: «/routing/nopage/style.css».

    Во-вторых, даже если мы подключим всё правильно, то ничего не произойдёт, и у нас всё ещё будет голая страница html. И вот тут мы подходим к самой последней части сегодняшней статьи — дополним скрипт, чтобы он ловил и обрабатывал запросы, которые браузер отправляет сам, читая разметку html. Ну и про favicon не забудем — возьмите фавиконку и положите её в /routing директорию нашего сервера.

    Итак, переходим опять в /routing/index.js . Теперь мы будем писать код прямо перед try/catch:

    // До этого мы уже получили path и prePath. Теперь осталось понять, какие запросы // мы получаем. Отсеиваем все запросы по точке, так чтобы туда попали только запросы к // файлам, например: style.css, test.js, song.mp3 if(/\./.test(path)) < if(path == 'favicon.ico') < // Если нужна фавиконка - возвращаем её, путь для неё всегда будет 'favicon.ico' // Получается, если добавить в начале prePath, будет: '/var/www/html/nodejs/routing/favicon.ico'. // Не забываем про return, чтобы сервер даже не пытался искать файлы дальше. let readStream = fs.createReadStream(prePath+path); readStream.pipe(res); return; >else< // А вот если у нас не иконка, то нам нужно понять, что это за файл, и сделать нужную // запись в res.head, чтобы браузер понял, что он получил именно то, что и ожидал. // На данный момент мне нужны css, js и mp3 от сервера, так что я заполнил только // эти случаи, но, на самом деле, стоит написать отдельный модуль для этого. if(/\.mp3$/gi.test(path)) < res.writeHead(200, < 'Content-Type': 'audio/mpeg' >); > else if(/\.css$/gi.test(path)) < res.writeHead(200, < 'Content-Type': 'text/css' >); > else if(/\.js$/gi.test(path)) < res.writeHead(200, < 'Content-Type': 'application/javascript' >); > // Опять же-таки, отдаём потом серверу и пишем return, чтобы он не шёл дальше. let readStream = fs.createReadStream(prePath+path); readStream.pipe(res); return; > > 

    Фух. Всё готово. Теперь можно подключить наш css-файл и увидеть нашу страницу 404 со всеми стилями:

    image

    Выводы

    Ура! Мы сделали свой веб-сервер, который работает, и работает хорошо. Разумеется, это только начало работы над приложением, но самое главное уже готово — на таком веб-сервере можно поднимать любые страницы, он справляется и со статикой, и с динамическим контентом, и роутинг, на мой взгляд, выглядит удобно — достаточно просто положить соответствующий файл в static или dynamic, и он тут же подхватится, и не надо писать роутинг для каждого конкретного случая.

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

    UPD: Я не призываю кого-либо использовать этот сервер на постоянной основе. Несмотря на то, что он полностью меня устраивает, в нём нет большого количества нужных для обычного веб-сервера функций и не оптимизирован некоторый готовый функционал, вроде внятного определения mime-типов. Это всё будет в следующих статьях.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *