Статьи

WebSockets в экосистеме Ruby

Руби учится любить WebSockets

Руби учится любить WebSockets

Какого черта «WebSocket», точно? Некоторые из нас слышали об изменениях, которые приходят в Rails в отношении WebSockets (например, Action Cable в Rails 5), но немного сложно точно определить, для чего предназначены WebSockets. Какую проблему они решают и как они вписываются в сферу HTTP, Интернета и Ruby? Это то, что мы рассмотрим в этой статье.

Почему?

Давайте наберем машину времени до начала Интернета. Еще в те времена, как мы все знаем, веб-сайты состояли из статических страниц с кучей ссылок между ними. Эти страницы называются «статическими», потому что ничего о них действительно не меняется для каждого пользователя. Сервер просто обслуживает одно и то же для каждого пользователя в зависимости от пути, который запрашивает пользователь. Мы быстро поняли, что такого рода вещи были бы хорошими и хорошими, если бы все, что мы хотели, чтобы Интернет был эквивалентом легко доступной книги, но мы могли бы сделать гораздо больше. Таким образом, с элементами ввода и CGI (Common Gateway Interface — способ взаимодействия внешних сценариев с веб-сервером) динамические элементы заполонили веб-страницы.

Теперь мы можем обработать входные данные и что-то с ними сделать. Поскольку веб-сайты стали более загруженными, мы поняли, что CGI довольно плохо масштабируется. Вместе с этим появилось множество вариантов, таких как FastCGI, для решения этой проблемы. Мы придумали всевозможные фреймворки, чтобы сделать написание бэк-эндов намного проще: Rails, Django и т. Д. Весь этот прогресс произошел, но в конце концов мы все еще обслуживали некоторый HTML (с помощью различных методов ), пользователь читал этот в основном статический HTML и затем запрашивал какой-то другой HTML.

Затем разработчики осознали всю мощь Javascript и связь с сервером через AJAX. Страницы больше не были просто каплями HTML. Вместо этого Javascript использовался для изменения содержимого этих страниц на основе асинхронного взаимодействия с сервером. Часто изменения состояния, которые произошли на сервере, должны были отражаться на клиенте. Возьмем очень простой пример. Может быть, мы хотим, чтобы уведомление отображалось на панели администратора, когда количество пользователей на сервере превышает определенный лимит. Однако методы, используемые для такого рода вещей, были не лучшими. Одним из распространенных решений был длинный опрос HTTP. С его помощью клиент (т. Е. Код Javascript, выполняемый в браузере) отправляет HTTP-серверу запрос, который сервер сохраняет открытым (т. Е. Сервер не отправляет никаких данных, но не закрывает соединение), пока не будет доступно какое-либо обновление ,

Возможно, вы задаетесь вопросом: зачем нам это ждать, если клиент может просто попросить сервер сообщить клиенту, когда появится обновление? Ну, к сожалению, HTTP не позволяет нам сделать это. HTTP не был разработан, чтобы быть управляемым сервером протоколом. Клиент отправляет запросы, HTTP-сервер отвечает на них. Период. Длительный опрос не является действительно хорошим решением, поскольку он вызывает всевозможные головные боли, когда дело доходит до масштабирования, переключения пользователей между Wi-Fi и сотовой связью и т. Д. Как мы решаем эту проблему, позволяя серверу общаться с клиентом?

WebSockets

Это где WebSockets входят в картину. Группа очень умных людей собралась и выяснила протокол, который можно использовать для двунаправленной связи между клиентом и сервером. Затем они записали это в RFC (т. Е. Request for Comments; это более или менее документация для различных частей Интернета), в частности RFC 6455 . Документ определяет TCP-подобный протокол, который позволяет серверу и клиенту обмениваться данными. Клиенту предоставляется определенный API для связи с сервером (известный как API WebSocket). Сила WebSockets становится очевидной, когда вы понимаете, что клиент теперь может создавать события на основе ввода с сервера. Хотите обновить свой интерфейс, когда акция достигает определенной цены? Нет проблем, просто попросите сервер сообщить клиенту о достижении этого предела и написать некоторый код, управляемый событиями.

Как все это работает вместе с HTTP? Большинство из них работает более или менее независимо от HTTP. Однако «рукопожатие» должно выполняться по HTTP. Если вы знакомы с TCP, вы знаете, что рукопожатие происходит, как только вы открываете новое соединение. Рукопожатие предназначено для обмена некоторой базовой информацией и установления соединения. Для WebSockets существует рукопожатие, чтобы сервер знал, что он должен открыть канал связи WebSocket с клиентом. HTTP используется для передачи этого сообщения с помощью специального запроса «HTTP Upgrade», который имеет некоторые поля, специфичные для WebSockets.

Но это означает, что HTTP-сервер, который мы используем, должен реализовывать WebSockets, наша веб-инфраструктура должна дать нам какой-то способ работы с соединениями WebSocket, и наш Javascript, работающий в браузере (который служит клиентом), должен иметь возможность говорить WebSocket.

Javascript и WebSockets

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

Javascript API WebSockets имеет довольно хорошую документацию от MDN . Хотя мы сосредоточены в основном на концепциях WebSockets, стоит взглянуть на API Javascript, так как большая часть знаний может быть повторно использована в бэкэнде (помните: WebSockets являются двунаправленными, поэтому мы я ожидал, что API на клиенте и сервере будет очень похожим). Мы можем создать объект WebSocket:

var socket = new WebSocket("ws://domain.com/server", "protocol") 

где «протокол» может быть заменен строкой, представляющей протокол, который обрабатывается данным сервером. Обратите внимание, что URL начинается с ws:// . Это относится к WebSockets с открытым текстом, wss:// может использоваться для WebSockets по SSL. Мы можем отправить данные тоже:

 socket.send("whatever") 

Самое главное, мы можем получать данные с сервера:

 socket.onmessage = function(ev) { console.log(ev.data); } 

Итак, поддержка Javascript довольно хорошая. Как насчет серверной части, где работает наш Ruby?

Ruby и WebSockets

Отношения между сообщениями в реальном времени и Ruby были сложными. Сообщество Ruby было взволновано, когда Node.js вырвался из ниоткуда и захватил тонну умственных способностей. Причина этого состояла не в том, что Node особенно приятнее для написания запуска веб-приложений. На самом деле, можно утверждать, что фреймворк, такой как Express, довольно трудоемок в использовании по сравнению с более полнофункциональными Rails. Но Node упростил взаимодействие в реальном времени и события. Я думаю, что Socket.io сыграл в этом огромное правило: клиенту и серверу стало легко и просто общаться без проблем. В течение довольно долгого времени Rails был за кривой, когда дело дошло до реального времени, и это все еще в некоторой степени. Но у нас есть несколько вариантов, которые делают возможным использование WebSockets в Rails.

Faye

Faye — это стандартное решение для реального времени и Rails. Хотя он использует так называемый протокол Байе, последние версии также включают стандартный сервер WebSocket . На самом деле, у нас была довольно недавняя серия, в которой подробно рассказывалось, как собрать приложение в реальном времени с использованием Faye.

EventMachine

EventMachine — это библиотека обработки событий для Ruby, которая также поддерживает связь на основе WebSocket с использованием em-websocket . Это довольно простой API, который позволяет нам довольно быстро создавать связь в реальном времени. У EngineYard есть хороший пост в блоге об использовании WebSockets с EventMachine.

Аутсорсинг

Эта техника немного противоречива. Идея состоит в том, что даже если вы используете Rails для большей части своего приложения, вам не нужно использовать его для компонентов обмена сообщениями в реальном времени. Для этого вы можете сделать что угодно (скажем, Node) и запустить его под другим поддоменом. Есть ряд причин, почему мне не нравится этот подход. Как правило, переключение контекста между двумя разными языками невероятно раздражает, особенно потому, что части вашего приложения в реальном времени и не в реальном времени, вероятно, тесно связаны. Во-вторых, при таком подходе дублирование кода осуществляется бесплатно, поскольку вам, возможно, придется переопределить некоторые из ваших моделей в Node, чтобы получить правильные данные в реальном времени. Однако есть несколько ситуаций, в которых подобные вещи имеют смысл. Если у вас есть в значительной степени традиционное веб-приложение с одним или двумя очень простыми компонентами реального времени, может быть целесообразно реализовать их в Node.

ActionCable

Это новый парень в квартале, который еще не совсем переехал. ActionCable — это одна из новых функций Rails 5, которая, в основном, позволяет нам без проблем использовать WebSockets в Rails. Однако у нас нет тонны информации о том, каким будет ActionCable, когда Rails 5 будет передан в наши руки (осень 2015 г.). Я определенно считаю, что ActionCable может помочь омолодить интерес к Rails в сообществе веб-разработчиков. Rails на некоторое время затмил тонну активности в мире Javascript / Node, тем более что в реальном времени и SPA стали названием игры. Надеюсь, это изменится.

Завершение

WebSockets — это довольно серьезная проблема, потому что они меняют наши взгляды на отношения клиент-сервер, когда речь заходит о HTTP. В некотором смысле они стирают различие между клиентом и сервером, устанавливая баланс между ними. Поскольку все больше браузеров реализуют стандарт WebSockets, они, вероятно, станут решающими для разработки веб-приложений. Надеемся, что эта статья дала вам представление о том, как появились WebSockets и как их использовать в экосистеме Ruby.