案例研究:Stream Congress 的实时更新
通过 WebSockets 和 EventSource ,HTML5 使开发人员能够构建与服务器实时通信的 Web 应用程序。 Stream Congress (可在 Chrome 网上应用店 中找到)提供有关美国国会运作的实时更新。它流式传输来自众议院和参议院的地板更新,相关新闻更新,国会议员的推文以及其他社交媒体更新。该应用程序旨在全天保持开放状态,因为它捕获了国会的业务。
从 WebSockets 开始
WebSockets 规范因其支持的功能而受到相当多的关注: 浏览器和服务器之间的稳定,双向 TCP 套接字 。TCP 套接字上没有强加任何数据格式;开发人员可以自由定义消息传递协议。实际上,将 JSON 对象作为字符串传递是最方便的。用于侦听实时更新的客户端 JavaScript 代码干净而简单:
var liveSocket = new WebSocket("ws://streamcongress.com:8080/live");
liveSocket.onmessage = function(payload) {
addToStream(JSON.parse(payload.data).reverse());
};
虽然浏览器对 WebSockets 的支持很简单,但服务器端支持仍处于形成阶段。 Socket.IO on Node.js 提供了最成熟、最强大的服务器端解决方案之一。像 Node.js 这样的事件驱动服务器非常适合 WebSockets。对于替代实现,Python 开发人员可以使用 Twisted 和 Tornado ,而 Ruby 开发人员则拥有 EventMachine 。
Cramp 简介
Cramp 是一个异步的 Ruby Web 框架,运行在 EventMachine 之上。它是由 Ruby on Rails 核心团队的成员 Pratik Naik 编写的。Cramp 为实时 Web 应用程序提供简单的领域特定语言 (DSL),是 Ruby Web 开发人员的理想选择。那些熟悉在 Ruby on Rails 中编写控制器的人会认识到 Cramp 的风格:
require "rubygems"
require "bundler"
Bundler.require
require 'cramp'
require 'http_router'
require 'active_support/json'
require 'thin'
Cramp::Websocket.backend = :thin
class LiveSocket < Cramp::Websocket
periodic_timer :check_activities, :every => 15
def check_activities
@latest_activity ||= nil
new_activities = find_activities_since(@latest_activity)
@latest_activity = new_activities.first unless new_activities.empty?
render new_activities.to_json
end
end
routes = HttpRouter.new do
add('/live').to(LiveSocket)
end
run routes
由于 Cramp 位于非阻塞事件机器之上,因此需要牢记以下几个注意事项:
- 必须使用非阻塞数据库驱动程序,如 MySQLPlus 和 em-mongo 。
- 必须使用事件驱动的 Web 服务器。内置了 对薄和 and 彩虹 的支持。
- Cramp 应用程序必须与支持 Stream Congress 的主 Rails 应用程序分开运行,重新启动并独立监控。
当前限制
WebSockets 在 2010 年 12 月 8 日遭遇挫折,当时一个安全漏洞被公布。 Firefox 和 Opera 都删除了浏览器对 WebSockets 的支持。虽然不存在纯 JavaScript polyfill,但 有一个 Flash 回退 已经被广泛采用。然而,依赖 Flash 远非理想。尽管 Chrome 和 Safari 继续支持 WebSockets,但很明显,要在不依赖 Flash 的情况下支持所有现代浏览器,WebSockets 需要被替换。
回滚到 AJAX 轮询
决定从 WebSockets 移回“老派”AJAX 轮询。虽然从磁盘和网络 I/O 的角度来看效率要低得多,但 AJAX 轮询简化了 Stream Congress 的技术实现。最重要的是,消除了对单独的 Cramp 应用程序的需求。AJAX 端点由 Rails 应用程序提供。客户端代码已修改为支持 jQuery AJAX 轮询:
var fillStream = function(mostRecentActivity) {
$.getJSON(requestURL, function(data) {
addToStream(data.reverse());
setTimeout(function() {fillStream(recentActivities.last());}, 15000);
});
};
但是,AJAX 轮询并非没有缺点。依赖 HTTP 请求/响应周期意味着即使没有任何新更新,服务器也能看到恒定负载。当然,AJAX 轮询并没有利用 HTML5 所提供的优势。
EventSource:适合的工具
到目前为止,关于 Stream Congress 的性质忽略了一个关键因素:应用程序只需要单向流式传输更新,从服务器到客户端 - 下游。它不需要是实时的上游客户端到服务器的通信。
从这个意义上说,WebSockets 对于 Stream Congress 来说是矫枉过正的。服务器到客户端的通信是如此普遍,以至于它被赋予了一个通用术语:推送。事实上,许多现有的 WebSocket 解决方案,从托管的 PusherApp 到 Rails 库 Socky ,都针对推送进行了优化,并且根本不支持客户端到服务器的通信。
输入事件源,也称为服务器发送的事件。该规范在上下文中与 WebSocket 相比具有优势,服务器到客户端推送:
- 浏览器端有一个类似的、简单的 JavaScript API。
- 打开的连接是基于 HTTP 的,不会下降到低级别的 TCP。
- 连接关闭时自动重新连接。
Going Back to Cramp
最近几个月,Cramp 增加了对 EventSource 的支持。该代码与 WebSockets 实现非常相似:
class LiveEvents < Cramp::Action
self.transport = :sse
periodic_timer :latest, :every => 15
def latest
@latest_activity ||= nil
new_activities = find_activities_since(@latest_activity)
@latest_activity = new_activities.first unless new_activities.empty?
render new_activities.to_json
end
end
routes = HttpRouter.new do
add('/').to(LiveEvents)
end
run routes
使用事件源时要记住的一个重要问题是不允许跨域连接。这意味着 Cramp 应用程序必须从与主 Rails 应用程序相同的 streamcongress.com 域提供服务。这可以通过 Web 服务器上的代理来实现。假设 Cramp 应用程序由 Thin 提供支持并在端口 8000 上运行,则 Apache 配置如下所示:
LoadModule proxy_module /usr/lib/apache2/modules/mod_proxy.so
LoadModule proxy_http_module /usr/lib/apache2/modules/mod_proxy_http.so
LoadModule proxy_balancer_module /usr/lib/apache2/modules/mod_proxy_balancer.so
<VirtualHost *:80>
ServerName streamcongress.com
DocumentRoot /projects/streamcongress/www/current/public
RailsEnv production
RackEnv production
<Directory /projects/streamcongress/www/current/public>
Order allow,deny
Allow from all
Options -MultiViews
</Directory>
<Proxy balancer://thin>
BalancerMember http://localhost:8000
</Proxy>
ProxyPass /live balancer://thin/
ProxyPassReverse /live balancer://thin/
ProxyPreserveHost on
</VirtualHost>
此配置将事件源终结点设置为 streamcongress.com/live
.
Stable Polyfill
与 WebSockets 相比,EventSource 最显着的优势之一是回退完全基于 JavaScript,不依赖于 Flash。Remy Sharp 的 polyfill 通过在原生不支持 EventSource 的浏览器中实现长轮询来实现这一点。因此,EventSource 今天可以在所有启用了 JavaScript 的现代浏览器上运行。
结论
HTML5 为许多新的和令人兴奋的 Web 开发可能性打开了大门。借助 WebSockets 和 EventSource,Web 开发人员现在拥有干净、定义明确的标准来支持实时 Web 应用程序。但并非所有用户都运行现代浏览器。选择实现这些技术时,必须考虑正常降级。WebSockets 和 EventSource 的服务器端工具仍处于早期阶段。在开发实时 HTML5 应用时,请务必牢记这些因素。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
上一篇: Chrome 实验演示工具
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论