Урок 10. Создание чата на NodeJS, SocketIO и VueJS. Вывод списка пользователей


Содержание материала:

Разрабатываем простой чат с помощью node.js и socket.io

Чтобы создать настоящее приложение чат, нужно разработать систему отправки и получения данных, которая будет работать в режиме реального времени. Будет невозможно это сделать без реляционной базы данных и вызова AJAX. Благодаря WebSocket и библиотеке socket.io, эта задача упрощается.

Весь код сегодняшнего урока можно найти на github .

Технологический комплекс

Для создания данного приложения вам понадобятся следующие инструменты:

WebSockets и socket.io

WebSockets — протокол, позволяющий осуществлять двусторонний синхронный обмен данными между клиентом и сервером.

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

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

Помимо node.js нам понадобится socket.io. Это библиотека, основанная на этом протоколе. Благодаря ей легче пользоваться WebSockets.

Элементы JavaScript

Node.js — серверная технология JavaScript, которая выполняется сервером на PHP, Ruby, Python. JavaScript использует события. Так как он также обладает этой характеристикой, с помощью node.js чат (его асинхронный код) будет написать проще.

У node.js есть собственный диспетчер пакетов: npm. С ним легче устанавливать, обновлять и удалять пакеты.

В этом туториале мы будем использовать express.js. Это небольшой веб-фреймворк, основанный на node.js.

Организация среды для разработки чата

Во-первых, нужно организовать среду разработки ПО.

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

npm запросит у вас некоторую информацию. Если вы хотите пропустить этот этап, нажимайте клавишу enter до конца. Теперь при взгляде на свой проект вы обнаружите новый файл: package.json. В нем перечислены все ваши зависимости.

Теперь можно установить пакеты, которые нужны для разработки нашего приложения! Нам понадобятся эти пакеты:

  • express: небольшой веб-фреймворк для node.js, чат с которым мы и будем создавать;
  • nodemon: пакет, который замечает все изменения и перезапускает сервер. Мы будем пользоваться им вместо классической команды node;
  • ejs: шаблонизатор, нужный для упрощения работы с HTML;
  • основу приложения составят node.js, socket.io: знаменитый пакет, который работает с WebSockets.

Добавить их в среду максимально легко:

То же самое нужно сделать с нашими 4 пакетами.

В package.json можно добавить эту строчку к ключу scripts:

Благодаря ней вы сможете запускать приложение при помощи одной команды, использующей nodemon:

Организация среды для разработки закончена. Теперь можно приступить к созданию приложения.

Приложение чат на node.js

Архитектура приложения

Для начала нам нужно разделить разработку приложения на 2 части: часть клиента и часть сервера. Нам нужно будет работать с этими частями, чтобы сделать рабочее приложение.

Сервер оставим на node.js, чат на первых этапах будет проектироваться им: он будет заниматься отправкой пакетов и веб-сайтом. Клиенту не будет виден этот код.

Часть клиента будет загружаться на компьютере клиента. У него будет прямой доступ к файлам (html/css и js).

Сторона сервера:

Нам нужно будет создать файл app.js, который запустит сервер и все пакеты.

Этот блок кода инициализирует наше экспресс-приложение. Если вы перейдете на http://localhost:3000 , то увидите сообщение.

Далее нужно настроить socket.io так, чтобы он был готов окунуться в мир WebSocket.

Здесь объект io даст нам доступ к библиотеке socket.io. Объект io теперь прослушивает каждое подсоединение к приложению. Каждый раз, когда подсоединяется новый пользователь, в нашей консоли появится сообщение «Подключился новый пользователь».

Если попробовать перезапустить сервер на локальной станции, ничего не произойдет… Почему? Потому что сторона клиента еще не готова.

Сейчас socket.io установлена только в части сервера. Далее проведем ту же работу на стороне клиента.

Сторона клиента:

Нам нужно лишь поменять одну строчку в app.js. По сути мы хотим отображать не сообщение «Привет, мир», а окно с чат-боксом, окном для ввода ника/сообщения и кнопкой отправки. Для этого нужно обработать HTML-файл (в нашем случае это будет ejs-файл) при получении доступа к корню / .

Нужно применить метод render к объекту res.

С другой стороны, нужно создать папку views с файлом index.ejs. CSS будет находиться в публичной папке:

Наш localhost:3000 будет выглядеть так:

Раз уж мы сделали простой шаблон, «можно установить» socket.io к каждому клиенту, который попытается подключиться к нашему серверу. Для этого нужно импортировать библиотеку socket.io на стороне клиента:

Мы будем работать с socket.io в файле .js. Единственный способ это сделать — добавить такие строчки:

Затем в публичной папке нужно добавить файл chat.js.

Теперь просто впишите там это:

Как вы могли догадаться, при запуске клиентом этого файла будет совершено автоматическое подключение, а значит — создан новый сокет.

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

Отправка и получение данных

Ник:

Когда пользователь будет подключаться к приложению, мы присвоим ему/ей ник по умолчанию, например, «anonymous». Для этого нужно будет перейти на сторону сервера (app.js) и добавить ключ к сокету. По сути сокет олицетворяет каждого клиента, который подключается к серверу.

Мы также будем прислушиваться ко всем вызовам, сделанным в «change_username». Если к этому событию будет отправлено сообщение, ник будет изменен.

На стороне клиента необходимо сделать обратное. При каждом клике на кнопку «change username» клиент должен будет отправить событие с новым значением.

Сообщение:

В случае с сообщениями работает тот же принцип!

Для нового события new_message мы вызываем атрибуты сокета io. Это означает, что все сокеты подключены. Эта строка будет отправлять сообщение всем сокетам. Нам нужно, чтобы сообщение было отослано всем пользователем (в том числе и отправителю).

Так в итоге будет выглядеть наше приложение с чатом:

Небольшое улучшение чата

Можно добавить небольшое улучшение, чтобы приложение выглядело реалистичнее. Мы добавим сообщение «ХХХ is typing. » («ХХХ набирает сообщение…»).

Это сделать очень просто.

После добавления HTML-элемента в index.ejs надо добавить слушатель событий jQuery, который будет детектировать момент набора сообщения и отправлять событие-сокет «typing».

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

Заключение

Как вы можете заметить, это приложение очень легко разработать. До того как я узнал о существовании WebSockets и socket.io, мне казалось, что для таких приложений очень сложно написать код!

Для улучшения приложения можно добавить следующие функции:

  • Система регистрации с возможностью переписываться в чат-руме один на один;
  • История всех бесед;
  • Ярлыки онлайн/оффлайн;
  • Скопировать все возможности WhatsApp.

Ультрабыстрые приложения на Node.js и Socket.io

Библиотека Socket.io позволяет реализовать синхронизированную коммуникацию внутри приложения. То есть, в режиме реального времени. Проще говоря, socket.io поможет создать живой чат на сайте. Или, например, браузерную игру, за развитием сюжета которой пользователь сможет следить без перезагрузки веб-страницы!

Что делает socket.io?

socket.io основывается на нескольких технологиях, обеспечивающих коммуникацию в режиме реального времени. Наиболее известная из них – это WebSocket.

Этот API JavaScript поддерживается всеми современными браузерами. Он обеспечивает синхронизированный двунаправленный обмен данными между клиентом и сервером.

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

Коммуникации обычно не синхронизированы : клиент запрашивает , а сервер отвечает

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

WebSocket – это технология, которая создаёт некое подобие «канала» коммуникации между клиентом и сервером, который остаётся постоянно открытым. Браузер и сервер остаются соединёнными друг с другом и могут обмениваться сообщениями в любом направлении.

С WebSocket канал связи между клиентом и сервером остаётся открытым .

Не путайте WebSocket и AJAX!

AJAX помогает клиенту и серверу обмениваться информацией без перезагрузки страницы. Но при этом клиент всегда посылает запрос, а сервер отвечает. Сервер не может сам принять решение об отправке данных клиенту. С WebSocket это стало возможным!

Топ-пост этого месяца:  Рейтинг Майл.ру — регистрация в top.mail.ru, настройка, получение кода счетчика и возможности

Socket.io позволяет просто использовать WebSocket. А поскольку не все браузеры могут создавать WebSocket, данная библиотека позволяет использовать другие механизмы синхронизации, которые поддерживаются браузером.

Загляните в раздел поддерживаемых браузеров на официальном сайте socket.io. Здесь можно увидеть, что библиотека определяет, какая технология подходит клиенту:

  • WebSocket;
  • Adobe Flash Socket;
  • Длинные опросы (long pooling) AJAX;
  • AJAX multipart streaming;
  • Iframe;
  • Опросы JSONP.

Например, если браузер не поддерживает WebSocket, но в нем установлен Flash, то socket.io будет использовать последнюю технологию для взаимосвязи в реальном времени. Если нет, библиотека применит другие техники, такие как длинные опросы AJAX.

Клиент постоянно опрашивает сервер, есть ли обновления для него. Это не самый эффективный метод, но он работает. Также может применяться невидимый iframe, который постоянно перезагружается, чтобы получить обновления с сервера.

Благодаря всем этим технологиям библиотека socket.io поддерживает большое количество браузеров, в том числе и устаревших:

  • Internet Explorer 5.5+;
  • Safari 3+;
  • Google Chrome 4+;
  • Firefox 3+;
  • Opera 10.61+;
  • Safari для iPhone и iPad;
  • Стандартный браузер Android.

Отправка и получение сообщений с помощью socket.io

Перейдём к делу: как использовать библиотеку socket.io?

Установка socket.io

При первом использовании библиотеки я потратил 15 минут, чтобы установить ее. Для этого нужно выполнить эту команду:

Первый код: клиент входит в систему

При работе с библиотекой socket.io используется одновременно два файла:

  • Серверный файл (например, app.js): он управляет соединениями сайта и клиентских приложений (браузеров).
  • Клиентский файл (например, index.html): он соединяет клиента с сервером и отображает результаты в браузере.

Сервер (app.js)

Вначале мы загружаем на сервер содержимое страницы index.html и отображаем ее клиенту, После этого грузим библиотеку socket.io и управляем ее событиями.

Что делает приведенный выше код:

  • Отправляет файл index.html, когда клиент просит изменить страницу в браузере.
  • Готовится получать запросы через socket.io. Когда мы устанавливаем соединение с помощью библиотеки, то выводим сообщение об этом в консоль.

Допустим, что пользователь открывает в браузере веб-страницу, на которой находится приложение (в данном случае http://localhost:8080). Мы отправляем ему файл index.html, страница загружается. Код JavaScript этого файла соединяется с сервером. Но на этот раз не через http, а через socket.io (WebSocket). Клиент поддерживает два типа соединений:

  • «Классическое» HTTP-соединение с сервером, которое используется для загрузки веб-страницы index.html.
  • Соединение, происходящее «в реальном времени» для открытия канала через WebSocket с помощью socket.io.

Клиент (index.html)

Файл index.html отправляется сервером Node.js. Это классический HTML-файл, который содержит JavaScript-код для соединения с сервером в режиме реального времени.

Я специально расположил JavaScript- код в конце HTML-кода, чтобы избежать задержки загрузки страницы из-за JavaScript.

В первом блоке кода мы получаем файл socket.io.js для клиента. Он автоматически предоставляется сервером Node.js через модуль socket.io (поэтому путь к файлу выбран не случайно):

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

Затем выполним действие на стороне клиента для установки соединения с сервером. Пока я сделал самое простое: соединился с сервером. Он располагается на моём компьютере, что объясняет адрес http://localhost:8080.

Тестируем код!

Затем в браузере откройте страницу с Node.js: http://localhost:8080

После этого загрузится основная страница. Затем компьютер откроет соединение с socket.io, а сервер выведет отладочную информацию в консоли:

Отлично! Значит, код работает.

Отправка и получение сообщений

Теперь можно обмениваться сообщениями между клиентом и сервером. Вот два возможных сценария:

  • Сервер хочет отправить сообщение клиенту.
  • Клиент хочет отправить сообщение серверу.

Сервер хочет отправить сообщение клиенту.

Я предлагаю рассмотреть вариант, когда сервер отправляет сообщение клиенту о том, что соединение установлено. Добавьте этот код в файл app.js:

Когда соединение установлено, клиенту отправляется сообщение с помощью socket.emit(). Эта функция принимает два параметра:

  • Тип сообщения, которое нужно передать. Это позволит различать типы сообщений. Например, в игре можно отправлять типы сообщений «move_player» или «attack_player».
  • Содержимое сообщения. Здесь можно указать всё, что хотите.

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

В файле index.html (на стороне клиента) мы будем отслеживать входящие сообщения:

С помощью socket.on() перехватываются сообщения типа message. Когда они приходят, вызывается функция, которая отображает простое диалоговое окно.

Попробуйте. Вы увидите, что при загрузке index.html отображается диалоговое окно, сообщающее, что соединение успешно установлено.

Клиент отображает сообщение от сервера в диалоговом окне

Клиент хочет отправить сообщение серверу.

На стороне клиента (в файле index.html) я добавлю кнопку «Poke the server». Когда мы нажмём на неё, серверу будет отправлено сообщение. Вот полный код:

Чтобы перехватить событие нажатия на кнопку, я использую jQuery. Вы можете использовать JavaScript.

Добавьте в код следующий блок:

Это простой код. При нажатии на кнопку на сервер отправляет сообщение типа message (вместе с контентом). Если нужно получить его на стороне сервера, придётся реализовать отслеживание сообщений типа message:

Запустите код. Нажмите на кнопку, размещенную на веб-странице, и понаблюдайте за консолью сервера. Вы должны увидеть следующий текст.

Когда клиент нажимает на кнопку , сервер мгновенно реагирует в консоли

Коммуникация с несколькими клиентами

В предыдущих примерах мы работали с одним сервером и одним клиентом. На практике у вас будет сразу несколько клиентов, соединённых с приложением Node.js. Чтобы воссоздать эту ситуацию локально, откройте две вкладки в браузере. На каждой из них перейдите по адресу http://localhost:8080. В результате сервер увидит соединения двух различных клиентов.

При работе с несколькими клиентскими соединениями нужно иметь возможность:

  • Отправлять сообщения всем клиентам одновременно. Мы называем это рассылкой.
  • Запоминать информацию о каждом клиенте (например, имя пользователя). Для этого нам потребуются переменные сессии.

Это как раз то, что о чем я расскажу дальше.

Отправка сообщения всем клиентам (рассылка)

Когда вызывается socket.emit() на стороне сервера, то отсылается сообщение только клиенту, с которым вы общаетесь в данный момент. Но можно отправить сообщение всем другим клиентам (кроме того, к которому вы сейчас подключены).

Рассмотрим следующий сценарий:

  1. Клиент A посылает сообщение серверу.
  2. Сервер анализирует его.
  3. Сервер решает сделать рассылку этого сообщения и отправляет его другим клиентам B и C.

В рассылке сервер отправляет сообщение всем другим соединённым клиентам

Например, клиент A пишет сообщение в чате и отправляет его на сервер. А чтобы его увидели другие клиенты, оно должно быть разослано.

Для этого нужно вызвать socket.broadcast.emit(), и сообщение будет отправлено другим пользователям. Добавьте приведенный ниже код рассылки в файл app.js:

Теперь попробуйте открыть в браузере несколько веб-страниц по адресу http://localhost:8080. Вы увидите, что, когда к серверу подключается новый клиент, другие страницы реагируют на это сообщением: «Another client has just connected!»

Переменные сессии

При многопользовательском подключении трудно идентифицировать каждого клиента. Идеальным вариантом была бы использовать переменные сессии. Но они недоступны в socket.io.

Хотя переменными сессии можно управлять из другой библиотеки через промежуточный слой session.socket.io .

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

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

Чтобы добавить переменную сессии на стороне сервера, необходим следующий код:

В этом примере мы храним данные в переменной объекта socket. Чтобы получить эту информацию, нужно просмотреть содержимое socket.myvariable:

Теперь попытаемся представить реальный случай использования. Когда клиент соединяется с сервером, веб-страница запрашивает его имя. Сервер сохраняет логин пользователя в переменной сессии, чтобы использовать его, когда клиент нажмёт на кнопку «Poke the server».

Давайте посмотрим, какие изменения нам нужно внести.

Веб-страница (index.html) отправляет сообщение, содержащее имя пользователя

Когда веб-страница загружается, запрашивается логин пользователя. Мы отправляем его на сервер с помощью сообщения типа «little_newbie» . Это сообщение содержит имя посетителя:

Сервер (app.js) хранит имя пользователя

Сервер должен получить это сообщение. Мы отслеживаем сообщения типа «little_newbie» и, когда его получаем, то сохраняем имя пользователя в переменной сессии:

Сервер (app.js) помнит имя пользователя, когда мы отправляем ему сообщение

Чтобы сервер помнил пользователя, когда он нажимает на кнопку, мы дополним функцию обратного вызова. Она вызывается при получении сервером сообщения типа «message»:

Как только сервер получает сообщение, мы запрашиваем переменную сессии с именем пользователя из клиентского объекта socket.

Тест кода

Попробуйте открыть два окна браузера и ввести разные имена пользователей. Затем нажмите на кнопку “Poke the server”. В консоли сервера вы увидите имя пользователя, который кликнул по кнопке.

Несколько пользователей подключены : сервер помнит их имена !

Знакомство с Node.JS: разработка чата

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

Давайте установим в наш проект еще парочку модулей которые помогут нам разрабатывать фронтенд и делать его красивым: для работы с DOM-элементами мы будем использовать библиотеку jQuery, для верстки — UIKit, а для анимации — Animate.css (можно обойтись и средствами UIKit, но мне их реализация не очень понравилась — многовато специфических багов которые не хочется разбирать). Переходим в консоли в папку с нашим проектом и ставим модули:

Топ-пост этого месяца:  WhatsApp обновил функцию групповых звонков, сделав их проще

Установили. Теперь подключим эти файлы во фронтенд.

При написании статьи заметил, что из репозиториев npm пропала версия UIKit 2, и устанавливается 3 с пометкой beta , поэтому в конце статьи приложу архив с нужным модулем, а вы его поместите в папку node_modules в корне вашего проекта, заменив 3ю версию 2й. Ну или если есть желание — можете переписать дальнейшую верстку под 3й — пожалуйста. Я пока жду релиза)

В папке /public/ открываем наш файл index.html и, удалив все наши «игрульки» из прошлых статей, подключаем все необходимые файлы. Получиться должно примерно так:

В хедере мы подключаем все необходимые css-стили, в футере, перед закрывающим тегом

Урок 10. Создание чата на NodeJS, SocketIO и VueJS. Вывод списка пользователей

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

Мы реализуем программу при помощи платформы Socket.io, а также Node JS и Express. Socket.IO — JavaScript-библиотека, выполняющая роль программы для обмена данными между клиентами и сервером. Все обновления происходят в режиме реального времени, что позволяет создавать функционал на подобии веб чата, онлайн игры или других мультиплеерных сервисов.

Благодаря сокетам мы можем отправлять данные на один сервер, а далее все клиенты (пользователи), подключенные к этому серверу, будут видеть всю информацию и взаимодействовать с ней. На основе Socket.IO можно создавать как небольшие чат программы, так и полноценные мультиплеерные игры, запускаемые через браузер.

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

Для установки Node перейдите на их официальный сайт и выполните установку программы на ваш компьютер.

Создайте папку и откройте её через командную строку или терминал. В командной строке пропишите команду npm init . У вас спросят различные настройки, введите их:

Далее выполните установку npm install express и npm install socket.io . Это два пакета, которые понадобятся для разработки программы.

Далее создайте два файла: index.js , а также index.html . Оба эти файла представлены ниже вместе с комментариями.

HTML код программы:

JavaScript код программы:

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

WebSocket

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

Более новая информация по этой теме находится на странице https://learn.javascript.ru/websocket.

Протокол WebSocket (стандарт RFC 6455) предназначен для решения любых задач и снятия ограничений обмена данными между браузером и сервером.

Он позволяет пересылать любые данные, на любой домен, безопасно и почти без лишнего сетевого трафика.

Пример браузерного кода

Для открытия соединения достаточно создать объект WebSocket , указав в нём специальный протокол ws .:

У объекта socket есть четыре колбэка: один при получении данных и три – при изменениях в состоянии соединения:

Для посылки данных используется метод socket.send(data) . Пересылать можно любые данные.

…Или файл, выбранный в форме:

Просто, не правда ли? Выбираем, что переслать, и socket.send() .

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

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

Установление WebSocket-соединения

Протокол WebSocket работает над TCP.

Это означает, что при соединении браузер отправляет по HTTP специальные заголовки, спрашивая: «поддерживает ли сервер WebSocket?».

Если сервер в ответных заголовках отвечает «да, поддерживаю», то дальше HTTP прекращается и общение идёт на специальном протоколе WebSocket, который уже не имеет с HTTP ничего общего.

Установление соединения

Пример запроса от браузера при создании нового объекта new WebSocket(«ws://server.example.com/chat») :

GET, Host Стандартные HTTP-заголовки из URL запроса Upgrade, Connection Указывают, что браузер хочет перейти на websocket. Origin Протокол, домен и порт, откуда отправлен запрос. Sec-WebSocket-Key Случайный ключ, который генерируется браузером: 16 байт в кодировке Base64. Sec-WebSocket-Version Версия протокола. Текущая версия: 13.

Все заголовки, кроме GET и Host , браузер генерирует сам, без возможности вмешательства JavaScript.

Создать подобный XMLHttpRequest-запрос (подделать WebSocket ) невозможно, по одной простой причине: указанные выше заголовки запрещены к установке методом setRequestHeader .

Сервер может проанализировать эти заголовки и решить, разрешает ли он WebSocket с данного домена Origin .

Ответ сервера, если он понимает и разрешает WebSocket -подключение:

Здесь строка Sec-WebSocket-Accept представляет собой перекодированный по специальному алгоритму ключ Sec-WebSocket-Key . Браузер использует её для проверки, что ответ предназначается именно ему.

Затем данные передаются по специальному протоколу, структура которого («фреймы») изложена далее. И это уже совсем не HTTP.

Расширения и подпротоколы

Также возможны дополнительные заголовки Sec-WebSocket-Extensions и Sec-WebSocket-Protocol , описывающие расширения и подпротоколы (subprotocol), которые поддерживает данный клиент.

Посмотрим разницу между ними на двух примерах:

Заголовок Sec-WebSocket-Extensions: deflate-frame означает, что браузер поддерживает модификацию протокола, обеспечивающую сжатие данных.

Это говорит не о самих данных, а об улучшении способа их передачи. Браузер сам формирует этот заголовок.

Заголовок Sec-WebSocket-Protocol: soap, wamp говорит о том, что по WebSocket браузер собирается передавать не просто какие-то данные, а данные в протоколах SOAP или WAMP («The WebSocket Application Messaging Protocol»). Стандартные подпротоколы регистрируются в специальном каталоге IANA.

Этот заголовок браузер поставит, если указать второй необязательный параметр WebSocket :

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

В ответе выше сервер указывает, что поддерживает расширение deflate-frame , а из запрошенных подпротоколов – только SOAP.

Соединение WebSocket можно открывать как WS:// или как WSS:// . Протокол WSS представляет собой WebSocket над HTTPS.

Кроме большей безопасности, у WSS есть важное преимущество перед обычным WS – большая вероятность соединения.

Дело в том, что HTTPS шифрует трафик от клиента к серверу, а HTTP – нет.

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

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

Формат данных

Полное описание протокола содержится в RFC 6455.

Здесь представлено частичное описание с комментариями самых важных его частей. Если вы хотите понять стандарт, то рекомендуется сначала прочитать это описание.

Описание фрейма

В протоколе WebSocket предусмотрены несколько видов пакетов («фреймов»).

Они делятся на два больших типа: фреймы с данными («data frames») и управляющие («control frames»), предназначенные для проверки связи (PING) и закрытия соединения.

Фрейм, согласно стандарту, выглядит так:

С виду – не очень понятно, во всяком случае, для большинства людей.

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

То есть, вот первые 32 бита:

Сначала идёт бит FIN (вертикальная надпись на рисунке), затем биты RSV1, RSV2, RSV3 (их смысл раскрыт ниже), затем «опкод», «МАСКА» и, наконец, «Длина тела», которая занимает 7 бит. Затем, если «Длина тела» равна 126 или 127, идёт «Расширенная длина тела», потом (на следующей строке, то есть после первых 32 бит) будет её продолжение, ключ маски, и потом данные.

А теперь – подробное описание частей фрейма, то есть как именно передаются сообщения:

Одно сообщение, если оно очень длинное (вызовом send можно передать хоть целый файл), может состоять из множества фреймов («быть фрагментированным»).

У всех фреймов, кроме последнего, этот фрагмент установлен в 0 , у последнего – в 1 .

Если сообщение состоит из одного-единственного фрейма, то FIN в нём равен 1 .

RSV1, RSV2, RSV3: 1 бит каждый

В обычном WebSocket равны 0 , предназначены для расширений протокола. Расширение может записать в эти биты свои значения.

Задаёт тип фрейма, который позволяет интерпретировать находящиеся в нём данные. Возможные значения:

  • 0x1 обозначает текстовый фрейм.
  • 0x2 обозначает двоичный фрейм.
  • 0x3-7 зарезервированы для будущих фреймов с данными.
  • 0x8 обозначает закрытие соединения этим фреймом.
  • 0x9 обозначает PING.
  • 0xA обозначает PONG.
  • 0xB-F зарезервированы для будущих управляющих фреймов.
  • 0x0 обозначает фрейм-продолжение для фрагментированного сообщения. Он интерпретируется, исходя из ближайшего предыдущего ненулевого типа.

Маска: 1 бит

Если этот бит установлен, то данные фрейма маскированы. Более подробно маску и маскирование мы рассмотрим далее.

Длина тела: 7 битов, 7+16 битов, или 7+64 битов

Если значение поле «Длина тела» лежит в интервале 0-125 , то оно обозначает длину тела (используется далее). Если 126 , то следующие 2 байта интерпретируются как 16-битное беззнаковое целое число, содержащее длину тела. Если 127 , то следующие 8 байт интерпретируются как 64-битное беззнаковое целое, содержащее длину.

Такая хитрая схема нужна, чтобы минимизировать накладные расходы. Для сообщений длиной 125 байт и меньше хранение длины потребует всего 7 битов, для бóльших (до 65536) – 7 битов + 2 байта, ну а для ещё бóльших – 7 битов и 8 байт. Этого хватит для хранения длины сообщения размером в гигабайт и более.

Ключ маски: 4 байта.

Если бит Маска установлен в 0, то этого поля нет. Если в 1 то эти байты содержат маску, которая налагается на тело (см. далее).

Данные фрейма (тело)

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

Примеры

Некоторые примеры сообщений:

Нефрагментированное текстовое сообщение Hello без маски:

В заголовке первый байт содержит FIN=1 и опкод=0x1 (получается 10000001 в двоичной системе, то есть 0x81 – в 16-ричной), далее идёт длина 0x5 , далее текст.

Топ-пост этого месяца:  Новый алгоритм на Яндекс.Картах поиск по товарам и услугам из прайса

Фрагментированное текстовое сообщение Hello World из трёх частей, без маски, может выглядеть так:

  • У первого фрейма FIN=0 и текстовый опкод 0x1 .
  • У второго FIN=0 и опкод 0x0 . При фрагментации сообщения, у всех фреймов, кроме первого, опкод пустой (он один на всё сообщение).
  • У третьего, последнего фрейма FIN=1 .

А теперь посмотрим на все те замечательные возможности, которые даёт этот формат фрейма.

Фрагментация

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

Например, идёт поиск в базе данных и что-то уже найдено, а что-то ещё может быть позже.

  • У всех сообщений, кроме последнего, бит FIN=0 .
  • Опкод указывается только у первого, у остальных он должен быть равен 0x0 .

PING / PONG

В протокол встроена проверка связи при помощи управляющих фреймов типа PING и PONG.

Тот, кто хочет проверить соединение, отправляет фрейм PING с произвольным телом. Его получатель должен в разумное время ответить фреймом PONG с тем же телом.

Этот функционал встроен в браузерную реализацию, так что браузер ответит на PING сервера, но управлять им из JavaScript нельзя.

Иначе говоря, сервер всегда знает, жив ли посетитель или у него проблема с сетью.

Чистое закрытие

При закрытии соединения сторона, желающая это сделать (обе стороны в WebSocket равноправны) отправляет закрывающий фрейм (опкод 0x8 ), в теле которого указывает причину закрытия.

В браузерной реализации эта причина будет содержаться в свойстве reason события onclose .

Наличие такого фрейма позволяет отличить «чистое закрытие» от обрыва связи.

В браузерной реализации событие onclose при чистом закрытии имеет event.wasClean = true .

Коды закрытия

Коды закрытия вебсокета event.code , чтобы не путать их с HTTP-кодами, состоят из 4 цифр:

1000 Нормальное закрытие. 1001 Удалённая сторона «исчезла». Например, процесс сервера убит или браузер перешёл на другую страницу. 1002 Удалённая сторона завершила соединение в связи с ошибкой протокола. 1003 Удалённая сторона завершила соединение в связи с тем, что она получила данные, которые не может принять. Например, сторона, которая понимает только текстовые данные, может закрыть соединение с таким кодом, если приняла бинарное сообщение.

Атака «отравленный кэш»

В ранних реализациях WebSocket существовала уязвимость, называемая «отравленный кэш» (cache poisoning).

Она позволяла атаковать кэширующие прокси-сервера, в частности, корпоративные.

Атака осуществлялась так:

Хакер заманивает доверчивого посетителя (далее Жертва) на свою страницу.

Страница открывает WebSocket -соединение на сайт хакера. Предполагается, что Жертва сидит через прокси. Собственно, на прокси и направлена эта атака.

Страница формирует специального вида WebSocket-запрос, который (и здесь самое главное!) ряд прокси серверов не понимают.

Они пропускают начальный запрос через себя (который содержит Connection: upgrade ) и думают, что далее идёт уже следующий HTTP-запрос.

…Но на самом деле там данные, идущие через вебсокет! И обе стороны вебсокета (страница и сервер) контролируются Хакером. Так что хакер может передать в них нечто похожее на GET-запрос к известному ресурсу, например http://code.jquery.com/jquery.js , а сервер ответит «якобы кодом jQuery» с кэширующими заголовками.

Прокси послушно проглотит этот ответ и закэширует «якобы jQuery».

В результате при загрузке последующих страниц любой пользователь, использующий тот же прокси, что и Жертва, получит вместо http://code.jquery.com/jquery.js хакерский код.

Поэтому эта атака и называется «отравленный кэш».

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

Поэтому придумали способ защиты – «маску».

Маска для защиты от атаки

Для того, чтобы защититься от атаки, и придумана маска.

Ключ маски – это случайное 32-битное значение, которое варьируется от пакета к пакету. Тело сообщения проходит через XOR ^ с маской, а получатель восстанавливает его повторным XOR с ней (можно легко доказать, что (x ^ a) ^ a == x ).

Маска служит двум целям:

  1. Она генерируется браузером. Поэтому теперь хакер не сможет управлять реальным содержанием тела сообщения. После накладывания маски оно превратится в бинарную мешанину.
  2. Получившийся пакет данных уже точно не может быть воспринят промежуточным прокси как HTTP-запрос.

Наложение маски требует дополнительных ресурсов, поэтому протокол WebSocket не требует её.

Если по этому протоколу связываются два клиента (не обязательно браузеры), доверяющие друг другу и посредникам, то можно поставить бит Маска в 0 , и тогда ключ маски не указывается.

Пример

Рассмотрим прототип чата на WebSocket и Node.JS.

HTML: посетитель отсылает сообщения из формы и принимает в div

Урок 1. Создание чата на NodeJS, SocketIO и VueJS. Настройка express сервера

Oyunçu kontrollarını göstərin

  • Tarixində dərc edildi 4 İyn 2020
  • Полный Премиум курс «Создание чата на NodeJS, SocketIO и VueJS» смотрите тут: webformyself.com/category/premium/javascript-premium/chatnodejs-premium/
    В данном уроке вы узнаете, как начать разработку чата на nodejs и фреймворке express.

В данном уроке вы узнаете, как создать сервер на express и в браузере отдавать index.html файл клиенту.
Также вы увидите базовую настройку рабочего окружения для NodeJS.

Şərh • 18

аа извиняюсь дизлайк снял, урок 1. думал и все))) тогда норм, вспомнил финальный урок видил лови лайк, там все четко спасибо

афигетить какое название и какой видос, да ты крут

Указал бы express еще в названии. интересовала чистая нода =ъ

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

Подойдёт ли телефон для этого чата?

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

Vladilen Minin Я про сам процесс разработки, можно ли разработать этот чат технологиями, которые доступны телефонам? (К примеру, кодить в Sololearn)

Здесь рассматриваются именно веб технологии, так что нативного мобильного чата конечно же не будет

Vladilen Minin Я имел ввиду именно разработку данного чата на телефоне

Айхас 47, да подойдёт. Только нужно будет сделать адаптивную вёрстку — немного подделать ту вёрстку, что дана в курсе

Хорошие лекции у автора. Лесс по ним учил. Не реклама, а констатация факта.

Ваня Иванов, спасибо за отзыв! Мы с командой стараемся работать над качеством

Создание чата на NodeJS, SocketIO и VueJS

Изучаем современные технологии веб-разработки на практическом примере, используя NodeJS, SocketIO, VueJS!

Описание :

В данном курсе мы разберем способ создания простого чата на платформе NodeJS.

Из основных технологий на сервере мы будем использовать SocketIO и фреймворк Express. На клиентской части мы будем использовать VueJS и библиотеку Materialize-css для создания Material Design.

В результате курса мы получим рабочий чат и разберем способ деплоя данного приложения на бесплатный облачный сервис Heroku, используя инструмент Heroku-CLI и систему контроля версий GIT для того, чтобы приложение было доступно удаленно на домене.

Урок 1. Создание чата на NodeJS, SocketIO и VueJS. Настройка express сервера

Oyunçu kontrollarını göstərin

  • Tarixində dərc edildi 4 İyn 2020
  • Полный Премиум курс «Создание чата на NodeJS, SocketIO и VueJS» смотрите тут: webformyself.com/category/premium/javascript-premium/chatnodejs-premium/
    В данном уроке вы узнаете, как начать разработку чата на nodejs и фреймворке express.

В данном уроке вы узнаете, как создать сервер на express и в браузере отдавать index.html файл клиенту.
Также вы увидите базовую настройку рабочего окружения для NodeJS.

Şərh • 18

аа извиняюсь дизлайк снял, урок 1. думал и все))) тогда норм, вспомнил финальный урок видил лови лайк, там все четко спасибо

афигетить какое название и какой видос, да ты крут

Указал бы express еще в названии. интересовала чистая нода =ъ

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

Подойдёт ли телефон для этого чата?

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

Vladilen Minin Я про сам процесс разработки, можно ли разработать этот чат технологиями, которые доступны телефонам? (К примеру, кодить в Sololearn)

Здесь рассматриваются именно веб технологии, так что нативного мобильного чата конечно же не будет

Vladilen Minin Я имел ввиду именно разработку данного чата на телефоне

Айхас 47, да подойдёт. Только нужно будет сделать адаптивную вёрстку — немного подделать ту вёрстку, что дана в курсе

Хорошие лекции у автора. Лесс по ним учил. Не реклама, а констатация факта.

Ваня Иванов, спасибо за отзыв! Мы с командой стараемся работать над качеством

Сделай своими руками

Создать аккаунт

Регистрация с помощью социальной сети

Урок 1. Создание чата на NodeJS, SocketIO и VueJS. Настройка express сервера

Спасибо! Поделитесь с друзьями!

Вам не понравилось видео. Спасибо за то что поделились своим мнением!

Описание

Полный Премиум курс «Создание чата на NodeJS, SocketIO и VueJS» смотрите тут: https://webformyself.com/category/premium/javascript-premium/chatnodejs-premium/

В данном уроке вы узнаете, как начать разработку чата на nodejs и фреймворке express.

В данном уроке вы узнаете, как создать сервер на express и в браузере отдавать index.html файл клиенту.

Также вы увидите базовую настройку рабочего окружения для NodeJS.

Создание чата на NodeJS, SocketIO и VueJS

Полный Премиум курс «Создание чата на NodeJS, SocketIO и VueJS» смотрите тут: webformyself.com/category/premium/javascript-premium/chatnodejs-premium/

В данном курсе мы разберем способ создать простой чат на платформе NodeJS.
Из основных технологий на сервере мы будем использовать SocketIO и фреймворк Express. На клиентской части мы будем использовать VueJS и библиотеку Materialize-css для создания Material Design.
В результате курса мы получим рабочий чат и разберем способ деплоя данного приложения на бесплатный облачный сервис Heroku, используя инструмент Heroku-CLI и систему контроля версий GIT для того, чтобы приложение было доступно удаленно на домене.

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