前端通信:SSE设计方案(二)--- 服务器推送技术的实践以及一些应用场景的demo(包括在线及时聊天系统以及线上缓存更新,代码热修复案例)
距离上一篇博客,这篇文章的发布大概过了整整三个月。下面废话不多说了,直接进入主题。
上一篇博客介绍了基础的纯概念,这篇文章纯粹偏技术实践,需要理解一些玩意的。技术介绍
- 客户端基础类库代码 -- SSE.js和ajax.1.7.js 客户端创建连接和定义监听的代码 以及结合ajax完成双工通道,完成双向都可推送
- node -- SSE_server.js node服务器代码,处理请求和消息推送
- nginx 作为测试服务器进行浏览器和局域网测试
官方文档和设计方案
SSE.js 代码改动(比较上一个版本)
// 抛出对象
var output = {
create:function (options) {
var param = tool.initParam(options),sendData = ''; if (param.data){
tool.each(param.data, function (item, index) {
sendData += (index + "=" + item + "&")
});
sendData = sendData.slice(0, -1);
} var es = new EventSource(param.url+'?'+sendData); es.addEventListener('open',function (e) {
param.openEvent(e)
}); es.addEventListener('message',function (e) {
param.messageEvent(e)
}); es.addEventListener('error',function (e) {
param.errorEvent(e)
es.close() // 关闭连接
}); // 创建用户自定义事件
if (param.customEvent.length > 0){
tool.each(param.customEvent,function (item) {
es.addEventListener(item.name,item.callback);
})
}
}
改动:
针对上一个版本,增加了数据验证以及一些参数的传递。虽然开启withCredentials可以传递信息的凭据,比如cookie,但是毕竟一个url,也是可以用url带参传递过去的,所以额外增加了这个玩意。so,这样我们就可以在非ie系列的浏览器上痛快的翱翔了。
PS:上面代码为创建的核心代码,其他代码可以到github上看,或者直接npm安装好了看。
客户端的准备工作搞好了,下一步就是服务器的工作了,因为一个技术肯定是多个技术配合才能完成的,不懂服务器的前端,不是好前端,这是我一项认可的事情。
下面为简易的node测试代码,没有那么追求精简,为了测试搞的。
var http = require("http");
var url=require('url');
var qs=require('querystring');//解析参数的库
var sendObject = {}, count = 0;
var gerry = {} // 向除自己的所有人推送信息
function sendAll(data) {
for (let index in sendObject){
if (data.name !== index){
sendObject[index].write("retry: " + data.retry + "\n");
if (data.event){
sendObject[index].write("event: " + data.event + "\n");
} let sengData = {
author:data.name,
data:data.data
}
sendObject[index].write("data: " + JSON.stringify(sengData) + "\n\n");
}
}
} // 聊天系统的demo推送测试
http.createServer(function (req, res) { var arg1=url.parse(req.url,true).query;
console.log(arg1.name);
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild');
res.setHeader('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS');
res.writeHead(200, {
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
"Connection": "keep-alive"
}); res.setTimeout(5000,()=>{
res.write(":this is test")
}) sendObject[arg1.name] = res;
}).listen(8074); // ajax双工执行发送机制
http.createServer(function (req, res) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild');
res.setHeader('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS');
res.writeHead(200,{
"content-type":"application/json; charset=utf-8"
});
var arr = []
new Promise(function(x,xx){
req.on("data",function(data){
arr.push(data);
}); req.on("end",function(){
var data= Buffer.concat(arr).toString(),ret;
try{
ret = JSON.parse(data);
x(ret)
}catch(err){}
})
}).then(function (req) {
var data = {
retry: 10000,
name: req.name,
data: req.message,
event:req.event
}
sendAll(data)
// res.write(Buffer.concat(arr).toString()) })
res.end()
}).listen(8075) var cacheUpdate = {} // 缓存更新和线上正在使用的代码热修复和强制用户重新请求去拉取最新代码
http.createServer(function (req, res) { var arg1=url.parse(req.url,true).query;
console.log(arg1.name);
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild');
res.setHeader('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS');
res.writeHead(200, {
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
"Connection": "keep-alive"
}); res.setTimeout(5000,()=>{
res.write(":this is test")
})
cacheUpdate[arg1.name] = res;
}).listen(8076); // 触发推送的动作
http.createServer(function (req, res) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild');
res.setHeader('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS');
res.writeHead(200,{
"content-type":"application/json; charset=utf-8"
});
var arr = []
new Promise(function(x,xx){
req.on("data",function(data){
arr.push(data);
}); req.on("end",function(){
var data= Buffer.concat(arr).toString(),ret;
try{
ret = JSON.parse(data);
x(ret)
}catch(err){}
})
}).then(function (req) {
var data = {
retry: 10000,
name: req.name,
data: req.message,
event:req.event
} cacheUpdate[data.name].write("retry: " + data.retry + "\n");
cacheUpdate[data.name].write("event: " + data.event + "\n");
cacheUpdate[data.name].write("data: " + data.data + "\n\n"); })
res.end()
}).listen(8077)
node服务器测试代码
最重要的环节开始了,下面就是我的show time。
1. 聊天系统的demo
介绍:既然服务器有了主动推送给客户端的能力,那么最重要的基础场景就是交流。所以这个聊天系统demo应运而生
使用的类库:ajax类库+sse类库(这里的ajax随便大家用什么通信类库,我这里使用的是我自己第一阶段研究的类库)
demo查看:https://github.com/GerryIsWarrior/SSE/blob/master/js-demo/index_chat.html
测试(模拟了2个人,只要服务器吃的消,多少人都可以):
总结: 这个聊天系统的demo,创建了2个用户,用左边用户进行发送,监控右边用户的控制台的network,可以查看到通信的请求,在左边用户每次发完消息之后,右边用户每次都接受到数据,然后处理到聊天系统界面。其实sse后端底层也类似于长连接,只是多了一个服务器可以反向推的动作。
2. 线上客户端缓存的更新demo
介绍:因为前端浏览器的机制,将所有用的数据请求过来,没有请求的页面也能跑起来。所以对于做前端优化的同学就明白一件事,希望用户能更多的缓存命中我们存储在用户浏览器中的一些数据,这样对于第一次加载之后,如果一些缓存数据没动的data,直接取出来,渲染到用户浏览器中。这样给用户的感觉就是秒开的感觉(大家可以参考京东网站的首页优化,首屏啊,二次打开等等)
使用类库:SSE.js+原生js+postMan去触发推送
demo查看:https://github.com/GerryIsWarrior/SSE/blob/master/js-demo/index_cache.html
测试(模拟localStory缓存用户数据更新)
总结:测试页面,首先我在代码中固定写了一个dom的我是基础缓存的数据,存到localStory中。然后对于这个打开我们的网页在线上的用户,我使用了postman往我的借口里发送数据,触发推送的动作,比如我的demo中就是发送了一个‘我试更新过的混存数据’,然后推送到客户端,然后客户端接收到这个event,然后更新缓存。这样就完成了线上缓存更新的方式。这样避免了让用户再刷一次页面(重新请求页面数据,比对缓存版本啥的),毕竟用户,才是我们的上帝。
3. 线上代码热修复以及生产版本更新提示用户重新拉取页面
介绍:对于现在更多的spa来说,浏览器下载结束了代码,你使用的代码就是浏览器下载的,如果这块前端代码是有问题的,那么生产跑得代码都是有问题代码,除非用户手动刷新页面,重新请求一个正确的生产代码。
demo查看:https://github.com/GerryIsWarrior/SSE/blob/master/js-demo/index_hotRepair.html
测试(模拟一个线上案例):
总结:这个案例就是这样,之前我们写死了线上代码要打8折,所以我们最后计算金额的时候就是按照8折去计算的。但是产品过来说,不应该这样啊,这TM不是打9折吗?这样公司会亏损严重的。然后大家都蒙蔽,修正发布。然后发现用户的页面还是8折,用户没刷新。尴尬.....
so,通过正在线上的推送,来进行代码的热修复。比如我推送了一个9折的信息,然后客户端接受处理了,哪怕正在线上的用户都按正确的9折来计算。挽回了公司的损失。
PS:如果线上改动太多太多了,不好进行局部热修复方案,只能让正在用的用户强制更新,拉新数据。
就像上图一样,用户点确定就重新刷新页面,拉取新代码。
浏览器的测试兼容结果:chrome,safair,opera,firefox都可以跑
结语:这是sse技术研究的第二阶段,可以在非IE系列的浏览器上都跑起来了,而且针对不同场景的操作和优化都有很多的想法。每个想法真正写成一个成熟的东西,都能让前端变得更好。第三阶段,暂时定为SSE的收尾阶段,解决一些兼容性问题和以后用户提出的新问题。其实,搞前端这么久了,我感觉针对每个技术本身,都不是什么很牛逼和好玩的技术,但是把许多单个的技术融合起来,这样就会发现新的大陆一样,能创造奇迹。
github地址: https://github.com/GerryIsWarrior/SSE 如果感觉好,或者能解决你的问题,可以点个star
最近感悟最深的一句话:我可能推动不了前端技术的进步,但是我可以让前端技术变得更美好.....共勉
前端通信:SSE设计方案(二)--- 服务器推送技术的实践以及一些应用场景的demo(包括在线及时聊天系统以及线上缓存更新,代码热修复案例)的更多相关文章
- HTML5中的SSE(服务器推送技术)
本文原链接:https://cloud.tencent.com/developer/article/1194063 SSE技术详解:一种全新的HTML5服务器推送事件技术 前言 概述 基本介绍 与We ...
- Web端服务器推送技术原理分析及dwr框架简单的使用
1 背景 “服务器推送技术”(ServerPushing)是最近Web技术中最热门的一个流行术语.它是继“Ajax”之后又一个倍受追捧的Web技术.“服务器推送技术”最近的流行跟“Ajax ”有着密切 ...
- 深入了解 Dojo 的服务器推送技术
国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html 内部邀请码:C8E245J (不写邀请码,没有现金送) 国 ...
- JavaEE开发之SpringMVC中的静态资源映射及服务器推送技术
在上篇博客中,我们聊了<JavaEE开发之SpringMVC中的自定义拦截器及异常处理>.本篇博客我们继续的来聊SpringMVC的东西,下方我们将会聊到js.css这些静态文件的加载配置 ...
- Server push(服务器推送技术)
一.服务器推送技术Server Push详解: 推送技术Server Push的基础思想是将浏览器主动查询信息改为服务器主动发送信息.服务器发送一批数据,浏览器显示这些数据,同时保证与服 ...
- web服务器推送技术
传统模式的 Web 系统以客户端发出请求.服务器端响应的方式工作.不能满足很多现实应用的需求,譬如: 监控系统:后台硬件温度.电压发生变化: 即时通信系统:其它用户登录.发送信息: 即时报价系统:后台 ...
- PHP Web实时消息后台服务器推送技术---GoEasy
越来越多的项目需要用到实时消息的推送与接收,怎样用php实现最方便呢?我这里推荐大家使用GoEasy, 它是一款第三方推送服务平台,使用它的API可以轻松搞定实时推送! 浏览器兼容性:GoEasy推送 ...
- Ruby Web实时消息后台服务器推送技术---GoEasy
越来越多的项目需要用到实时消息的推送与接收,怎样用Ruby实现最方便呢?我这里推荐大家使用GoEasy, 它是一款第三方推送服务平台,使用它的API可以轻松搞定实时推送! 浏览器兼容性:GoEasy推 ...
- 基于comet服务器推送技术(web实时聊天)
http://www.cnblogs.com/zengqinglei/archive/2013/03/31/2991189.html Comet 也称反向 Ajax 或服务器端推技术.其思想很简单:将 ...
随机推荐
- JAVA NIO学习二:通道(Channel)与缓冲区(Buffer)
今天是2018年的第三天,真是时光飞逝,2017年的学习计划还没有学习完成,因此继续开始研究学习,那么上一节我们了解了NIO,那么这一节我们进一步来学习NIO相关的知识.那就是通道和缓冲区.Java ...
- 从底层角度看ASP.NET-A low-level Look at the ASP.NET...
从更低的角度 这篇文章在一个底层的角度来关注一个web请求怎样到达asp.net框架,从web服务器,通过ISAPI.看看这些后面发生了什么,让我们停止对asp.net的黑箱猜想.ASP.NET是一个 ...
- Keras 学习之旅(一)
软件环境(Windows): Visual Studio Anaconda CUDA MinGW-w64 conda install -c anaconda mingw libpython CNTK ...
- mayavi安装
Mayavi是python的一个包,提供方便的可视化方案.目前(20150809)Mayavi还没有py3的支持,以下安装环境在python 2.7.10下进行 安装Mayavi: 1. 通过pip ...
- Python学习_13_继承和元类
继承 继承的含义就是子类继承父类的命名空间,子类中可以调用父类的属性和方法,由于命名空间的查找方式,当子类中定义和父类同名属性或者方法时,子类的实例调用的是子类中的属性,而不是父类,这就形成了pyth ...
- Struts简介、原理及简单实现
struts简介 Struts是Apache软件基金会(ASF)赞助的一个开源项目.它最初是jakarta项目中的一个子项目,并在2004年3月成为ASF的顶级项目.它通过采用JavaServlet/ ...
- Python入门-数据类型之字符串
字符串详解 没那么多废话,直接介绍字符串使用.继续往下看~~~ 字符串定义: *1.引号包围,不可变(指的是不可以对字符串进行修改)得序列(凡是能够通过索引取值的都是序列). *2.不可变对象(字符串 ...
- Python玩转硬件:TPYBoard-Micropython开发板大盘点
学习python能做什么? 可以快速搭建一个漂亮的网站 可以写爬虫 实现微信机器人助手 可以实现很多自动化的任务 -- IEEE发布2017年编程语言排行榜:Python更是高居首位,那么Python ...
- JS文本框每隔4个数字加一个空格,银行卡号文本框
<input type="text" onkeypress="return (function(key,that){return (key>47&&a ...
- Python进阶内容(二)--- 装饰器
谈装饰器前,需要明白一件事,Python 中的函数和 Java.C++不太一样,Python 中的函数可以像普通变量一样当做参数传递给另外一个函数,例如: def foo(): print(" ...