哈喽!昨天我见识到了一种我以前从没见过的从服务器推送事件的炫酷方法:服务器推送事件server-sent events!如果你只需要让服务器发送事件,相较于 Websockets,它们或许是一个更简便的选择。
我会聊一聊它们的用途、运作原理,以及我昨日在试着运行它们的过程中遇到的几个错误。
(资料图)
问题:从服务器流式推送更新现在,我有一个启动虚拟机的 Web 服务,客户端轮询服务器,直到虚拟机启动。但我并不想使用轮询方式。
相反,我想让服务器流式推送更新。我跟 Kamal 说我要用 Websockets 来实现它,而他建议使用服务器推送事件不失为一个更简便的选择!
我登时就愣住了——那什么玩意???听起来像是些我从来没见过的稀罕玩意儿。于是乎我就查了查。
服务器推送事件就是个 HTTP 请求协议下文便是服务器推送事件的运作流程。我-很-高-兴-地了解到它们就是个 HTTP 请求协议。
1.客户端提出一个 GET 请求(举个例子)https://yoursite.com/events
2.客户端设置Connection: keep-alive
,这样我们就能有一个长连接 3.服务器设置设置一个Content-Type: text/event-stream
响应头 4.服务器开始推送事件,就比如下文这样:
event: statusdata: one
举个例子,这里是当我借助curl
发送请求时,一些服务器推送事件的样子:
$ curl -N "http://localhost:3000/sessions/15/stream"event: pandadata: oneevent: pandadata: twoevent: pandadata: threeevent: elephantdata: four
服务器可以根据时间推移缓慢推送事件,并且客户端也能够在它们到来时读取它们。你也可以将 JSON 或任何你想要的东西放在事件当中,就比如data: {"name": "ahmed"}
。
线路协议真的很简单(只需要设置event:
和data:
,或者如果你愿意,可设置为id:
和retry:
),所以你并不需要任何花里胡哨的服务器库来实现服务器推送事件。
以下是用于流式服务器推送事件的浏览器 JavaScript 的代码。(我从服务器推送事件的 MND 页面得到的这个范例)
你可以订阅所有事件,也可以为不同类型的事件使用不同的处理程序。这里我有一个只接受类型为panda
的事件的处理程序(就像我们的服务器在上一节中推送的那样)。
const evtSource = new EventSource("/sessions/15/stream", { withCredentials: true })evtSource.addEventListener("panda", function(event) { console.log("status", event)});
客户端在中途不能推送更新不同于 Websockets,服务器推送事件不允许大量的来回事件通讯。(这体现在它的字眼中 ——服务器推送所有事件)。初始的时候客户端发出一个请求,然后服务器发出一连串响应。
如果 HTTP 连接结束,它会自动重连使用EventSource
发出的 HTTP 请求和常规 HTTP 请求有一个很大的区别,MDN 文档中对此有所说明:
默认情况下,如果客户端和服务器之间的连接断开,则连接会重启。请使用
.close()
方法来终止连接。
很奇怪,一开始我真的被它吓到了:我打开了一个连接,然后在服务器端将其关闭,然后两秒过后客户端向我的传送终端发送了另一条请求!
我觉得这里可能是因为连接在完成之前意外断开了,所以客户端自动重新打开了它以防止类似情况再发生。
所以如果你不想让客户端继续重试,你就得通过调用.close()
直截了当地关闭连接。
你还能在服务器推送事件中设置id:
和retry:
字段。似乎,如果你在服务器推送事件上设置,那么当重新连接时,客户端将发送一个Last-Event-ID
响应头,带有它收到的最后一个 ID。酷!
我发现W3C 的服务器推送事件页面令人惊讶地容易理解。
在设置服务器推送事件的时候我遇到了两个错误我在 Rails 中使用服务器推送事件时遇到了几个问题,我认为这些问题挺有趣的。其中一个缘于 Nginx,另一个是由 Rails 引起的。
问题一:我不能在事件推送的过程中暂停
这个奇怪的错误是在我做以下操作时出现的:
def handler # SSE is Rails" built in server-sent events thing sse = SSE.new(response.stream, event: "status") sse.write("event") sleep 1 sse.write("another event")end
它会写入第一个事件,但不能写入第二个事件。我对此-非-常-困-惑,然后放开脑洞,试着理解 Ruby 中的sleep
是如何运作的。但是 Cass 将我引领到一个与我有着相同困惑的Stack Overflow 问答帖,而这里包含了让我为之震惊的回答!
事实证明,问题出在我的 Rails 服务器位于 Nginx 之后,似乎 Nginx 默认使用 HTTP/1.0 向上游服务器发起请求(为啥?都 2021 年了,还这么干?我相信这其中一定有合乎情理的解释,也许是为了向下兼容之类的)。
所以客户端(Nginx)会在服务器推送第一个事件之后直接关闭连接。我觉得如果在我推送第二个事件的过程中没有暂停,它继续正常工作,基本上就是服务器在连接关闭之前和客户端在争速度,争着推送第二部分响应,如果我这边推送速度足够快,那么服务器就会赢得比赛。
我不确定为什么使用 HTTP/1.0 会使客户端的连接关闭(可能是因为服务器在每个事件结尾写入了两个换行符?),但因为服务器推送事件是一个比较新的玩意儿,HTTP/1.0 (这种老旧协议)不支持它一点都会不意外。
设置proxy_http_version 1.1
从而解决那个麻烦。好欸!
问题二:事件被缓冲
这个事情解决完,第二个麻烦接踵而至。不过这个问题实际上非常好解决,因为 Cass 已经建议将stackoverflow 里另一篇帖的回答作为前一个问题的解决方案,虽然它并没有是导致问题一出现的源头,但它-确-实-解-释-了问题二。
问题在这个示例代码中:
def handler response.headers["Content-Type"] = "text/event-stream" # Turn off buffering in nginx response.headers["X-Accel-Buffering"] = "no" sse = SSE.new(response.stream, event: "status") 10.times do sse.write("event") sleep 1 endend
我本来期望它每秒返回 1 个事件,持续 10 秒,但实际上它等了 10 秒才把 10 个事件一起返回。这不是我们想要的流式传输方式!
原来这是因为 Rack ETag 中间件想要计算 ETag(响应的哈希值),为此它需要整个响应为它服务。因此,我需要禁用 ETag 生成。
Stack Overflow 的回答建议完全禁用 Rack ETag 中间件,但我不想这样做,于是我去看了链接至 GitHub 上的议题。
那个 GitHub 议题建议我可以针对仅流式传输终端应用一个解决方法,即Last-Modified
响应头,显然,这么做可以绕过 ETag 中间件。
所以我设置为:
headers["Last-Modified"] = Time.now.httpdate
然后它起作用了!!!
我还通过设置响应头X-Accel-Buffering: no
关闭了位于 Nginx 中的缓冲区。我并没有百分百确定我要那样做,但这么做似乎更安全。
起初,我全身心致力于从头开始调试这两个错误。Cass 为我指向了那两个 Stack Overflow 帖子,一开始我对那些帖下提出的解决方案持怀疑态度(我想:“我没有使用 HTTP/1.0 啊!ETag 响应头什么玩意,跟这一切有关系吗??”)。
但结果证明,我确实无意中使用了HTTP/1.0,并且 Rack ETag 中间件确实给我带来了问题。
因此,也许这个故事告诉我,有时候计算机就是会以奇怪的方式相互作用,其它人在过去也遇到过计算机以完全相同的奇怪方式相互作用的问题,而 Stack Overflow 有时会提供关于为什么会发生这些情况的答案 : )
我认为重要的是不要随意从 Stack Overflow 中尝试各种解决方案(当然,在这种情况下不会有人建议这样做!)。对于这两个问题,我确实需要去仔细思考,了解发生了什么,还有为什么更改这些设置会起作用。
就是这样!今天我要继续着手实现服务器推送事件,因为昨天一整天我都沉浸在上述这些错误里。好在我学到了一个以前从未听说过的易学易用的网络技术,心里还是很高兴的。
关键词:
推荐内容
- 服务器推送事件:一种从服务器流式推送事
- 新疆各地消防救援部门开展形式多样防灾减
- 王志飞儿子:父亲成名后“抛妻弃子”,进
- 【全球热闻】新旅界简讯|第二批国家级文
- 兼具现代绿色发展理念与古代科技人文特色
- 沉香玉弃妃难宠江小湖网盘_沉香玉弃妃难
- 天天微头条丨18.98-27.98万元 比亚迪海
- 中超|大连人战平沧州雄狮 世界热讯
- 天天新资讯:受害者隐私不该成八卦谈资
- 长江健康:5月9日融资买入262.86万元,融
- 这个夏天,“趣恩施 嗨一夏”!
- 武仙传(关于武仙传介绍)
- 失业保险金去哪里领取?可以领取几个月?
- 微信通知结婚邀请语_结婚邀请函模板范文_
- 苹果将发布iOS16.5RC版,支持呼叫Siri录
- 济宁市住建局开展建筑工地施工现场防汛专
- 夏天吃什么水果最解暑?
- 从农村到城市去带孩的这些老人他们有养老
- 热点评!同学两亿岁第二季_同学两亿岁第
- 聚焦:治疗双向情感障碍,阿立哌唑2个月
- 列车命案死者亲属:赔偿基本已谈成,究竟
- 环球聚焦:王充论文与道文言文翻译_王充
- 直击股东大会|商务男装不行了? 报喜鸟
- 蛊林巴奇介绍_蛊林巴奇|世界热闻
- 5月9日新股速递 焦点速递
- 焦点简讯:午睡过久会长胖吗?研究发现:
- 如何安装 Regent MS80 运动灯
- 雷鸣山表态:风光储将成三峡未来发力重点
- LE SSERAFIM夺日本公信榜周冠军 第二次
- 国家统计局:2022年城镇私营单位就业人员
- 外交部发言人宣布加拿大驻上海总领馆一名
- 国家统计局:去年全国规模以上企业就业人
- 世界滚动:瓜分携程
- 世界今日报丨中国检察机关办案发现房屋买
- 龙蟠科技: 主要客户有宁德时代、瑞浦兰
- 实时:微信二维码可以收分付吗_微信支付
- 想在北京私立初中借读需要满足哪些条件?
- 辽宁出入境检验检疫局体检中心_辽宁出入
- 环球最资讯丨适合5月种植的蔬菜有哪些?
- 环球讯息:从内到外全面升级 深蓝S7增程
- 戏剧点亮城市,美育绽放梦想!静安区将打
- 砚溪镇
- 世界今热点:消费电子板块震荡走强 兆威
- 江西庐山现壮阔瀑布云景观
- “小管线”增创“大效益”-环球最新
- 讯息:四胞胎宝妈产后9个月再怀四胞胎
- 专访汇丰中国副行长兼工商金融总监马健:
- 早间公告:翔丰华向不特定对象发行可转债
- 正常光照下,手机亮度应控制在50%!看手
- 英国零售协会:4月份零售销售保持稳定增长
- 果然学长女朋友照片_果然学长女朋友
- 焦点热讯:航空公司,腰伤,被辞退,还要
- 【天天报资讯】期货夜盘收盘 国内期货主
- 重庆水务,重庆水务股票
- 宝马公布一季度财报:M系列热度较高,营
- 建三江插秧忙 北大荒种下“二十连丰”新
- 速看:外交部发言人:美国绝不是尊重和保
- 房企年报透视|物业管理:外拓面积增长,物
- 针对色情等问题,网信部门进驻斗鱼平台开
- 天天热议:中国著名导演万玛才旦因病离世
- 列车命案死者亲属:赔偿基本已谈成,究竟
- 环球聚焦:王充论文与道文言文翻译_王充
- 直击股东大会|商务男装不行了? 报喜鸟
- 蛊林巴奇介绍_蛊林巴奇|世界热闻
- 5月9日新股速递 焦点速递
- 焦点简讯:午睡过久会长胖吗?研究发现:
- 如何安装 Regent MS80 运动灯
- 雷鸣山表态:风光储将成三峡未来发力重点
- LE SSERAFIM夺日本公信榜周冠军 第二次
- 国家统计局:2022年城镇私营单位就业人员
- 外交部发言人宣布加拿大驻上海总领馆一名
- 国家统计局:去年全国规模以上企业就业人
- 世界滚动:瓜分携程
- 世界今日报丨中国检察机关办案发现房屋买
- 龙蟠科技: 主要客户有宁德时代、瑞浦兰
- 实时:微信二维码可以收分付吗_微信支付
- 想在北京私立初中借读需要满足哪些条件?
- 辽宁出入境检验检疫局体检中心_辽宁出入
- 环球最资讯丨适合5月种植的蔬菜有哪些?
- 环球讯息:从内到外全面升级 深蓝S7增程
- 戏剧点亮城市,美育绽放梦想!静安区将打
- 砚溪镇
- 世界今热点:消费电子板块震荡走强 兆威
- 江西庐山现壮阔瀑布云景观
- “小管线”增创“大效益”-环球最新
- 讯息:四胞胎宝妈产后9个月再怀四胞胎
- 专访汇丰中国副行长兼工商金融总监马健:
- 早间公告:翔丰华向不特定对象发行可转债
- 正常光照下,手机亮度应控制在50%!看手
- 英国零售协会:4月份零售销售保持稳定增长
- 果然学长女朋友照片_果然学长女朋友
- 焦点热讯:航空公司,腰伤,被辞退,还要
- 【天天报资讯】期货夜盘收盘 国内期货主
- 重庆水务,重庆水务股票
- 宝马公布一季度财报:M系列热度较高,营
- 建三江插秧忙 北大荒种下“二十连丰”新
- 速看:外交部发言人:美国绝不是尊重和保
- 房企年报透视|物业管理:外拓面积增长,物
- 针对色情等问题,网信部门进驻斗鱼平台开
- 天天热议:中国著名导演万玛才旦因病离世
- 白城景点排行榜_白城景点 微动态
- “美版AT1债券”遭抛售!危机未除,美国
- 禹州市组织召开2023年公用事业违规收费专
- 今日热闻!智商税学习机再见,作业帮推出2
- 环球今日讯!堪培拉的房价中位数可以带您
- NBA季后赛次轮G4掘金将客战太阳 天天时快讯
- 蚂蚁的特点和习性是什么_蚂蚁的特点
- 关注:日本下调新冠病毒防疫等级 与季节
- 攀岩世界杯雅加达站:中国小将王欣尚摘银
- 天天速递!美国银行业危机是否会继续蔓延
- 打败唐三的几种方法,如果你穿越到斗罗大
- 天天日报丨qq能上网页打不开_怎么解决
- 云南鹤庆两儿童走失?警方:系骑自行车外
- 【天天时快讯】供应链及供应链管理的含义
- 证券板块拉升 中国银河涨停
- 【东海期货5月8日产业链日报】贵金属篇:
- 当前报道:沃太能源毛利率波动下滑:规模
- 本周中东部开启晴朗升温模式 西部降水发
- 围棋练习专注力吗_围棋练习|天天热门
- Gurman:苹果 iPhone 16 Pro/Max 必