在过去几个月与许多开发人员讨论之后,我意识到他们中的很大一部分人不知道什么是“服务器发送的事件”(或“SSE”,或“EventSource”)。我在这里的目的是提供您可能需要的关于服务器发送事件的所有信息。第一个是…
你为什么还要学SSE?
随着经济和用户的实时性越来越强,如果向用户显示最后一次数据更新可能会更改其操作,则需要服务器发送事件。数据本身不需要经常更改,但当它更改时,您真的希望用户知道它!
在解释技术细节之前,让我们先看一些案例:
- –用户可以单击可用的最后一条新闻,而不是关闭页面。
- –服务/产品可用性。如果你为这个特定的客户销售罕见的产品或服务(汽车共享、自行车共享码头、有限库存的促销活动等等),你要确保你的潜在客户知道它是尽快可用的。
- –价格
- –社交/聊天…无需解释!
- –您可能只想显示快速变化的数据:游戏得分、交易、仪表板,…
“我不在乎你的”Server-Sent stuff“,我有WebSocket!”
waiting Ok,WebSockets现在很流行,很快,很容易实现,但是:
- 这意味着你已经明白你需要比HTTP轮询更好的东西。很好!
- WebSocket和SSE有其优缺点。我建议你读这篇博文然后回来…我会等你…
如果你懒惰,这里有一个非常简短的总结。WebSockets是双向的(你不需要双向的),而不是HTTP(一些代理不允许它通过“协议”,没有错误处理的标准)。SSE是单向(服务器到客户端)的HTTP协议,具有错误处理标准。两者都极大地提高了用户的延迟。从服务器负载的角度来看,与WebSockets(一台服务器处理的最终用户数更多)相比,使用SSE可以获得更好的性能。
“我不在乎你的”Server-Sent stuff“,我会要求每半秒!”
…现在我们需要解释一下服务器发送的事件是什么。
那么Server-Sent Events是什么?
客户端从服务器订阅“流”,服务器将向客户端发送消息(“事件流”),直到服务器或客户端关闭流。例如,一旦数据发生变化,服务器就可以决定何时以及向客户端发送什么。
要完全理解SSE,我们需要解释轮询。接收信息的“历史”方法是询问。古老的“请求/响应”范例!当您轮询时,客户端请求信息,而服务器返回可用的信息。不问问就没办法得到什么。使用AJAX,可以使轮询以预定义的频率进行。
(为了优化服务器负载和带宽,如果自上次客户端请求以来内容没有更改,您可以决定服务器回答“没有内容”…但这意味着您的API不再是RESTful…:)。
比较轮询、长轮询和SSE消息以进行实时更新
好吧,目前的民意调查有五个主要结果:
- –您将对服务器负载收取过高的费用。很难对SSE和“机关枪”轮询进行基准比较,因为它取决于轮询的频率、数据本身、服务器配置等。当我们比较不同的场景时,我们得到的结果是3到10倍:一个SSE服务器可以处理比轮询服务器多3到10倍的用户(具有相同的目标延迟)。
- –您将用无用的数据过度加载网络,因为即使没有更改,轮询也会发送数据!这不利于服务器端和客户端的成本,也不利于地球(这可能就是我写这篇博文的原因吧!)!你知道网络环境足迹相当于40个核电站的能源消耗和整个民用飞行的温室气体排放吗。
- 同样,将轮询与流式处理进行基准测试取决于数据集,但我们已经在各种公共api上对其进行了测试,其增益从20%(所有数据都经常更改,我们只是保存头和往返)到95%(数据集的一小部分变化不太频繁)。
- –推送比投票消耗的终端用户电池少75%到95%(这是研究报告)…你不希望你的用户继续使用你的应用吗?
- –轮询需要3次往返(TCP SIN、SSL和数据)。在3G中,一次往返需要150毫秒,因此一次投票需要450毫秒,然后手机才能接收到任何有用的数据。一旦与SSE建立了连接,移动设备将在75ms内接收到新数据(因为数据直接从服务器发送到客户端)。
- –最后但并非最不重要的是:你不会为你的代码感到骄傲!
TLDR:轮询以显示实时数据感觉如下:
对于长轮询(挂起GET/COMET),服务器将在发送响应之前等待数据的更改。服务器将“保持”该请求,直到有意义地发送某些内容为止。它看起来可能很有吸引力,因为您可以减轻无用的响应,但它需要一些技巧(例如在“无限”iframe上附加脚本标记)和服务器负载,这些仍然是巨大的。如何处理“更新”队列、丢失的消息和断开的连接?
那么,为什么不使用为实时下游而构建的W3C标准呢?
我们将首先查看消息本身,然后是客户端实现,最后是服务器端实现。
Event-stream(服务器发送事件消息的酷名称)
事件流是一个简单的文本数据流,必须使用UTF-8编码。事件流中的消息由一对换行符(“\n”)分隔。
规范中定义了以下字段名:
- 事件:事件的类型。它将允许您对不同的内容使用相同的流。客户机可以决定只“监听”一种类型的事件,或者对每种事件类型进行不同的解释。
- 数据:消息的数据字段。您可以放置连续的“数据”行。
- ID:每个事件流的ID。有助于跟踪丢失的邮件。
- 重试:在所有连接丢失后,浏览器尝试新连接之前要使用的时间(毫秒)。重新连接过程是自动的,默认设置为3秒。在这个重新连接过程中,最后一个接收到的ID将自动发送到服务器……您需要自己用WebSockets或长轮询编写一些代码。
“:”:如果以冒号开头的消息,将被视为注释
一些例子
data: hello word\n\n
data: first line\n data: second line\n\n
id: 12345 event: newuser data: {user name : JohnDoe}\n data: {user name : JohnDoe2}\n\n
是的,您可以轻松地发送JSON格式而不破坏synthax!这是一个非常好的消息!
id: 12345 event: newuser data: { \n data: first name : John, \n data: last name : Doe \n data: }\n\n
客户端
浏览器
由于服务器发送事件是定义基于Web的API的W3C标准,因此Web的客户端非常简单和直接。
下面是从这个链接中获取的一个示例。它处理到服务器的连接、侦听消息和处理这些消息。
var source = new EventSource('/stats'); source.onopen = function() { connectionOpen(true); }; source.onerror = function () { connectionOpen(false); }; source.addEventListener('connections', updateConnections, false); source.addEventListener('requests', updateRequests, false); source.addEventListener('uptime', updateUptime, false); source.onmessage = function (event) { // a message without a type was fired };
一个问题是所有浏览器都不支持EventSource
来源:http://caniuse.com/#search=Server sent
因此,您必须测试您的用户浏览器是否支持SSE
if(typeof(EventSource) !== “undefined”) { //Yeah … SSE supported! } else { //wtf! Let’s make a polyfill }
如果浏览器不支持SSE,则可以使用Polyfill。我们已经测试了GitHub中提供的几个版本,并决定将这个版本用于我们自己的sdk:
对于更多的代码示例,您可以查看我们自己的SDK或演示(使用D3.js进行测试,显示财务数据)
移动应用程序
对于移动应用程序,没有标准的API。事情有点复杂,所以我最好的选择是提供指向库的链接和其他一些详细说明代码示例的博客文章。
安卓
A simple app based on SSE on GitHub
An app using Server-sent events to get data from GitHub API
网间网操作系统
An app using Server-sent events to get data from the New York Times API.
结论
我们提倡使用高标准,我们相信每个人(包括开发人员)在消耗不必要的资源之前都应该三思而后行。当应用程序/网站需要实时更新一些数据,而不需要向上的数据流时,应首先考虑服务器发送的事件。如果您不同意,请在下面评论这篇文章,我们会很高兴地回答。
原文:https://apifriends.com/api-streaming/server-sent-events/
本文:http://jiagoushi.pro/node/963
讨论:请加入知识星球或者微信圈子【首席架构师圈】
- 登录 发表评论
- 103 次浏览
最新内容
- 4 days 23 hours ago
- 6 days 21 hours ago
- 1 week ago
- 1 week 1 day ago
- 1 week 1 day ago
- 1 week 1 day ago
- 1 week 2 days ago
- 1 week 2 days ago
- 1 week 2 days ago
- 1 week 2 days ago