前端通信: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 或服务器端推技术.其思想很简单:将 ...
随机推荐
- Spark源码剖析(六):Worker原理与源码剖析
上篇文章我们剖析了Master的原理和源码,知道了当Master使用资源分配算法将资源分配完成后,就会给对应的Worker发送启动Driver或者Executor的消息,那么Worker收到这些消息后 ...
- override与重载(overload)的区别
重载是相同函数名字.参数或参数类型不同,进行多次承载以适应不同的需要.(orerload)是面向过程的重载. (override)是面向对象的重载.是进行基类中的函数重写.
- 在表格中,th scope="row"和th scope="col"中的scope属性的用法及意义
把表头和数据联系起来:scope,id,headers属性就我用到现在,很多表格要比上面提供的例子复杂的多.让例子复杂一点,我会移去"Company"表头,并且把第一列的数据移到表 ...
- redis资料收集
http://www.runoob.com/redis/redis-sets.html redis set 使用 https://www.cnblogs.com/wanzaixiaoxin/p/49 ...
- springmvc注入类 NoUniqueBeanDefinitionException: No qualifying bean of type [] is defined: expected single错误
在springmvc中注入服务时用@Service 当有两个实现类时都标明@Service后则会出现异常: nested exception is org.springframework.beans. ...
- zabbix2.2部署安装(安装环境Centos 6.* X64)
1.在已有的LAMP或者LNMP的基础上安装zabbix,安装一些依赖包: 安装epel源:rpm -ivh http://dl.fedoraproject.org/pub/epel/6/x86_64 ...
- spring boot 之热部署(三)
热部署:当发现程序修改时自动启动应用程序. spring boot使用的是spring-boot-devtools是一个为开发者服务的一个模块.其原理用了classLoader 其中一个加载不变的类, ...
- 前端开发chrome console的使用 :评估表达式 – Break易站
本文内容来自:chrome console的使用 :评估表达式 – Break易站 从 DevTools 控制台使用它的某个评估功能查看页面上任意项目的状态. DevTools 控制台让您可通过特定方 ...
- 如何在MicroPython TPYBoard 添加自定义类库
开始之前,首先要感谢一下TPYBoard技术交流群(157816561)-云之初晓网友的分享. 今天简单分享下如何将自己编写的一些Python脚本的类库添加到固件中,在使用时只需import调用, ...
- SQL Server 禁用扩展存储过程
概述 扩展存储过程是 SQL Server 实例可以动态加载和运行的 DLL.扩展存储过程是使用 SQL Server 扩展存储过程 API 编写的,可直接在 SQL Server 实例的地址空间中运 ...