Node.js и Websockets являются идеальной комбинацией для написания очень быстрых приложений без задержек, которые могут отправлять данные огромному количеству клиентов. Так почему бы нам не начать изучать эти две темы с создания службы чата! Мы увидим, как установить пакеты Node.js, предоставить клиенту статическую страницу с базовым веб-сервером и настроить Socket.io для взаимодействия с клиентом.
Почему стоит выбрать Node.js и Socket.io?
Так зачем использовать это комбо?
Существует множество платформ, на которых можно запускать приложение чата, но, выбрав Node.js, нам не нужно изучать совершенно другой язык, это всего лишь JavaScript, но на стороне сервера.
Node.js — это платформа, основанная на среде выполнения Chrome JavaScript, которая упрощает создание приложений на JavaScript, которые работают на сервере. Node.js использует управляемую событиями неблокирующую модель ввода / вывода, что делает ее идеальной для создания приложений реального времени.
Все больше и больше приложений Node.js пишутся с учетом коммуникации в реальном времени. Известным примером является BrowserQuest от Mozilla, MMORPG, полностью написанная на Node.js, чей исходный код был выпущен на Github .
Node.js поставляется со встроенным менеджером пакетов: npm . Мы будем использовать его для установки пакетов, которые помогут ускорить процесс разработки наших приложений.
Для этого урока мы будем использовать три пакета: Jade, Express и Socket.io.
Socket.io: плагин Node.js Websockets
Главной особенностью нашего приложения является связь в реальном времени между клиентом и сервером.
HTML5 вводит Websockets, но он далеко не поддерживается всеми пользователями, поэтому нам нужно решение для резервного копирования.
Socket.io — это наше решение для резервного копирования: оно будет проверять совместимость Websocket и, если оно не поддерживается, будет использовать Adobe Flash, AJAX или iFrame.
Наконец, он поддерживает очень большой набор браузеров:
- Internet Explorer 5.5+
- Safari 3+
- Google Chrome 4+
- Firefox 3+
- Опера 10.61+
- iPhone Safari
- iPad Safari
- Android WebKit
- WebOs WebKit
Он также предлагает очень простые функции для взаимодействия между сервером и клиентом с обеих сторон.
Давайте начнем с установки трех пакетов, которые нам понадобятся.
Установка наших зависимостей
Npm позволяет нам устанавливать пакеты очень быстро, используя одну строку, поэтому сначала перейдите в ваш каталог и попросите npm загрузить необходимые пакеты:
1
|
npm install express jade socket.io
|
Теперь мы можем начать создавать наш серверный контроллер для обслуживания главной страницы.
Мы собираемся сохранить весь код на стороне сервера в файл "server.js"
который будет выполнен Node.js.
Обслуживание одной статической страницы
Для обслуживания нашей статической страницы мы будем использовать Express , пакет, который упрощает весь процесс отправки страницы на сервер.
Итак, давайте включим этот пакет в наш проект и запустим сервер:
1
|
var express = require(‘express’), app = express.createServer();
|
Далее нам нужно настроить Express для обслуживания страницы из репертуарных представлений с помощью движка шаблонов Jade, который мы установили ранее.
По умолчанию Express использует файл макета, но он нам не нужен, потому что мы будем обслуживать только одну страницу, поэтому вместо этого мы отключим его.
Express также может служить статическим реперторием для клиента, как классический веб-сервер, поэтому мы отправим "public"
папку, которая будет содержать все наши JavaScript, CSS и файлы изображений.
1
2
3
4
5
6
|
app.set(‘views’, __dirname + ‘/views’);
app.set(‘view engine’, ‘jade’);
app.set(«view options», { layout: false });
app.configure(function() {
app.use(express.static(__dirname + ‘/public’));
});
|
Далее, давайте создадим две папки внутри папки нашего проекта с именами "public"
и "views"
.
Теперь нам просто нужно настроить Express для обслуживания файла "home.jade"
, который мы создадим через мгновение, а затем настроить Express для прослушивания определенного порта.
Я буду использовать порт 3000, но вы можете использовать все, что вы предпочитаете.
1
2
3
4
|
app.get(‘/’, function(req, res){
res.render(‘home.jade’);
});
app.listen(3000);
|
Создание страницы шаблона Jade
Node.js использует шаблоны для обслуживания веб-страниц. Полезно отправлять динамические страницы и создавать их быстрее.
В этом уроке мы будем использовать Jade . Его синтаксис очень понятен и поддерживает все, что нам нужно.
«Jade — это высокопроизводительный шаблонизатор, находящийся под сильным влиянием Haml и реализованный с помощью JavaScript для Node».
Теперь я не буду подробно останавливаться на Jade. Если вам нужна дополнительная помощь, вы можете найти очень хорошо написанную документацию по репозиторию Github .
Конфигурация нефрита
Мы установили Jade ранее, но нам нужно включить его в наш файл server.js
как мы это сделали для Express.
По соглашению, мы включаем наши библиотеки вверху нашего файла, чтобы использовать их позже, без необходимости проверять, включены ли они уже. Поэтому поместите следующий код в "server.js"
файла "server.js"
:
1
|
var jade = require(‘jade’);
|
И это завершает нашу конфигурацию Jade. Express уже настроен на использование Jade с нашими файлами представлений, для отправки HTML-ответа нам просто нужно создать этот файл.
Создание нашей домашней страницы
Если мы запустим наш сервер сейчас, он выйдет из строя, потому что мы просим наше приложение отправить страницу, которая еще не существует.
Мы не собираемся создавать полнофункциональную страницу, просто что-то простое с заголовком, контейнером для сообщений, текстовой областью, кнопкой отправки и счетчиком пользователя.
"home.jade"
страницу "home.jade"
внутри папки "views"
со следующим кодом:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
doctype 5
html
head
title Chat
script(src=’https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js’)
script(src=»/socket.io/socket.io.js»)
script(src=»script.js»)
body
div.container
header
h1 A Chat application with Node.js and Socket.io
input(type=’text’)#pseudoInput
button#pseudoSet Set Pseudo
div#chatEntries
div#chatControls
input(type=’text’)#messageInput
button#submit Send
|
«Джейд это все об отступах»
Нефритовый язык — все об отступах. Как видите, нам не нужно закрывать наши контейнеры, достаточно сделать отступ для дочернего элемента родительского контейнера.
Мы также используем точку "."
и знак решетки "#"
чтобы указать класс или идентификатор элемента, как в файле CSS.
Мы также ссылаемся на три сценария в верхней части файла. Первый — это jQuery из Google CDN, затем у нас есть скрипт Socket.io, который автоматически обслуживается пакетом, и, наконец, файл "script.js"
котором будут храниться все наши пользовательские функции JS.
Конфигурация на стороне сервера Socket.io
Socket.io основан на событиях, как и Node. Он направлен на то, чтобы сделать приложения реального времени возможными в любом браузере и мобильном устройстве, стирая грани между этими различными транспортными механизмами. Это беззаботный, в режиме реального времени, и 100% JavaScript.
Как и другие модули, нам нужно включить его в наш файл server.js
. Мы также будем подключаться к нашему экспресс-серверу для прослушивания соединений с того же адреса и порта.
1
|
var io = require(‘socket.io’).listen(app);
|
Первое событие, которое мы будем использовать, это событие подключения. Он запускается, когда клиент пытается подключиться к серверу; Socket.io создает новый сокет, который мы будем использовать для получения или отправки сообщений клиенту.
Давайте начнем с инициализации соединения:
1
2
3
|
io.sockets.on(‘connection’, function (socket) {
//our other events…
});
|
Эта функция принимает два аргумента: первый — событие, а второй — функция обратного вызова с объектом сокета.
Используя такой код, мы можем создавать новые события на клиенте и на сервере с помощью Socket.io. Мы установим событие "pseudo"
событие "message"
далее.
Чтобы сделать это, это действительно просто, мы просто используем тот же синтаксис, но на этот раз с нашим объектом socket
а не с объектом "io.sockets"
(с «s»). Это позволяет нам общаться конкретно с одним клиентом.
Итак, внутри нашей функции подключения давайте добавим код события "pseudo"
.
1
2
3
|
socket.on(‘setPseudo’, function (data) {
socket.set(‘pseudo’, data);
});
|
Функция обратного вызова принимает один аргумент, это данные от клиента, и в нашем случае она содержит pseudo
. С помощью функции "set"
мы присваиваем переменную сокету. Первый аргумент — это имя этой переменной, а второй — значение.
Далее нам нужно добавить код для события "message"
. Он получит псевдо-пользователя, рассылает массив всем клиентам, который содержит полученное нами сообщение, а также псевдо-пользователя, и регистрирует его в нашей консоли.
1
2
3
4
5
6
7
|
socket.on(‘message’, function (message) {
socket.get(‘pseudo’, function (error, name) {
var data = { ‘message’ : message, pseudo : name };
socket.broadcast.emit(‘message’, data);
console.log(«user » + name + » send this : » + message);
})
});
|
Это завершает нашу конфигурацию на стороне сервера. Если вы хотите, вы можете пойти дальше и использовать другие события, чтобы добавить новые функции в чат.
Приятной особенностью Socket.io является то, что нам не нужно беспокоиться об обработке отключений клиентов. Когда он отключается, Socket.io больше не будет получать ответы на сообщения «heartbeat» и будет деактивировать сеанс, связанный с клиентом. Если это было просто временное отключение, клиент будет повторно подключен и продолжит сеанс.
Конфигурация Socket.io на стороне клиента
Теперь, когда наш сервер настроен на управление сообщениями, нам нужен клиент для их отправки.
Клиентская сторона Socket.io почти такая же, как и серверная. Он также работает с пользовательскими событиями, и мы будем создавать те же, что и на сервере.
Итак, сначала создайте файл "script.js"
внутри общей папки. Мы будем хранить все наши функции внутри него.
Сначала нам нужно запустить соединение socket.io между клиентом и сервером. Он будет храниться в переменной, которую мы будем использовать позже для отправки или получения данных. Когда для соединения не передаются никакие аргументы, оно автоматически подключится к серверу, который будет обслуживать страницу.
1
|
var socket = io.connect();
|
Далее, давайте создадим некоторые вспомогательные функции, которые нам понадобятся позже. Первая — это простая функция добавления сообщения на экран с псевдо-пользователем.
1
2
3
|
function addMessage(msg, pseudo) {
$(«#chatEntries»).append(‘<div class=»message»><p>’ + pseudo + ‘ : ‘ + msg + ‘</p></div>’);
}
|
Этот помощник использует функцию добавления из jQuery, чтобы добавить div
в конце #chatEntries div
.
Теперь мы собираемся написать функцию, которую мы можем вызывать, когда хотим отправить новое сообщение.
1
2
3
4
5
6
7
8
|
function sentMessage() {
if ($(‘#messageInput’).val() != «»)
{
socket.emit(‘message’, $(‘#messageInput’).val());
addMessage($(‘#messageInput’).val(), «Me», new Date().toISOString(), true);
$(‘#messageInput’).val(»);
}
}
|
Сначала мы проверяем, что наша текстовая область не пуста, затем мы отправляем пакет с именем "message"
на сервер, который содержит текст сообщения, мы печатаем его на экране с помощью нашей функции "addMessage"
и, наконец, удаляем весь текст из текстовая область.
Теперь, когда клиент открывает страницу, нам нужно сначала установить псевдо-пользователя. Эта функция отправит псевдо на сервер и покажет текстовую область и кнопку отправки.
1
2
3
4
5
6
7
8
9
|
function setPseudo() {
if ($(«#pseudoInput»).val() != «»)
{
socket.emit(‘setPseudo’, $(«#pseudoInput»).val());
$(‘#chatControls’).show();
$(‘#pseudoInput’).hide();
$(‘#pseudoSet’).hide();
}
}
|
Кроме того, мы скрываем элементы управления псевдоустановками, когда они отправляются на сервер.
Теперь, как и на стороне сервера, нам нужно убедиться, что мы можем получать входящие сообщения, и на этот раз мы будем печатать их на экране. Мы будем использовать тот же синтаксис, но на этот раз мы "addMessage"
функцию "addMessage"
.
1
2
3
|
socket.on(‘message’, function(data) {
addMessage(data[‘message’], data[‘pseudo’]);
});
|
Как и в случае с нашей конфигурацией сервера, пакет, отправляемый клиенту, представляет собой массив, содержащий сообщение и псевдо. Поэтому мы просто вызываем нашу "addMessage"
передавая сообщение и псевдо, которые мы извлекаем из полученного пакета данных.
Теперь нам просто нужно добавить функцию инициализации, которая запускается после полной загрузки страницы.
1
2
3
4
5
|
$(function() {
$(«#chatControls»).hide();
$(«#pseudoSet»).click(function() {setPseudo()});
$(«#submit»).click(function() {sentMessage();});
});
|
Сначала мы скрываем элементы управления чатом до установки псевдо, а затем устанавливаем двух прослушивателей, которые прослушивают щелчки на наших двух кнопках отправки. Первый предназначен для псевдо, а второй — для сообщений.
И это завершает наш клиентский скрипт.
Вывод
Теперь у нас есть работающий чат-сервис. Чтобы запустить его, просто запустите следующую команду:
1
|
node server.js
|
В вашем терминале вы должны получить сообщение от Socket.io о том, что сервер запущен. Чтобы увидеть вашу страницу, перейдите на 127.0.0.1:3000
(или какой порт вы выбрали ранее).
Дизайн очень простой, но вы можете легко добавить в таблицу стилей переходы CSS3 для входящих сообщений, звуки HTML5 или Bootstrap из Twitter.
Как видите, серверные и клиентские скрипты довольно похожи: это сила Node.js. Вы можете создать приложение без необходимости писать код дважды.
Наконец, вы, возможно, заметили, что в нашем файле server.js
потребовалось всего 25 строк кода для создания функционального приложения чата с потрясающей производительностью Это очень короткий, но это также работает очень хорошо.
Теперь, если вам интересно, я создал лучшее приложение для службы чата с хорошим дизайном и некоторыми дополнительными функциями. Он размещен на Nodester, а исходный код — на Github .
Вот предварительный просмотр этого.
Спасибо за прочтение.