序言javascript
传统web浏览器应用采用客户端主动请求方式,只有在收到浏览器请求时服务端才返回消息,这种模式已经不能知足日益多样化的web应用需求,例如:html
在线聊天系统:须要实时获取聊天消息。html5
实时监控系统:须要实时获取监控对象状态。如仪表读数、告警信息等。java
随着html技术演进,发展出了多种服务器推送技术,用于服务器向浏览器客户端推送消息。node
Ajax轮询nginx
采用Ajax定时向服务端发送请求检查有无消息更新。网页定时向服务器发送请求,若服务器有消息推送,则返回消息,不然返回空消息,以下图所示:git
这种轮询方式须要发送大量无效请求,大大消耗了服务器资源,且推送消息的实时性较低。github
Ajax长轮询web
Ajax长轮询对前面的Ajax轮询方式作了改进,服务端收到请求后,再也不当即返回,而是等待有消息推送时返回。网页收到服务端返回的消息后,当即发起一个新的请求,等待下一个推送消息。后端
采用这种方式的服务端实现比前者复杂,须要维护一个客户端创建的链接列表,当产生对某个客户端的推送消息后找到对应的链接并发送。优点是减小了轮询消耗,发送事件的实时性获得加强。
Server-Send Event
Server-Send Event是html5标准新增的技术,它延用了Ajax长轮询的思路,并对其进行了一些规范。Server-Send Event让服务端能够向客户端流式发送文本消息,并在发送完一个消息后保持请求不结束,链接始终保持。以下图所示:
网页调用EventSource接口向服务器发送请求:
var source = new EventSource('http://localhost:8080');
source.addEventListener('message', function(e) { console.log(e.data); }, false);
服务器返回的Content-Type头必须为text/event-stream,且返回完一个消息后不关闭请求,后续消息仍然使用同一个请求返回。浏览器会自动以换行符识别每一个消息。
响应头
Content-Type: text/event-stream
X-Accel-Buffering: no
响应体
event: userlogin
data: {"username": "John123"}
event: message
data: 123
若是服务端返回的消息经过nginx等代理服务器返回给客户端时,可能受到nginx缓存机制的影响。某些状况下,nginx会将服务端返回体缓存起来,等待全部返回接受完毕后再统一返回给客户端,在server-send event状况下将致使客户端没法及时接收到消息。须要在返回头中添加X-Accel-Buffering: no,以防止nginx作缓存。
使用华为API gateway提供
Server-Send Event类型的
API服务创建后端服务
登陆华为云https://console.huaweicloud.com/,建立弹性云服务器
输入apt install nodejs安装nodejs,使用nodejs建立服务器,并输入下列示例代码。
var http = require("http");
http.createServer(function (req, res) {
if (req.url === "/stream") {
res.writeHead(200, {
"Content-Type":"text/event-stream",
"X-Accel-Buffering":"no",
});
res.write("data: " + (new Date()) + "\n\n");
interval = setInterval(function () {
res.write("data: " + (new Date()) + "\n\n"); 12 }, 1000);
req.connection.addListener("close", function () {
clearInterval(interval);
}, false);
}
}).listen(8080);
上面代码是服务器每秒向客户端发送时间的示例。将上面的代码保存为server.js,而后执行nodejs server.js &
就启动了监听在8080端口的服务器。
添加安全组
将8080端口添加到安全组规则,使得外部能够访问云服务器的8080端口。
建立API
API网关提供从内网访问云服务器的能力,不须要申请公网弹性IP,就能够经过VPC通道开放API。
登陆华为云https://console.huaweicloud.com/apig/ ,首先建立VPC通道,端口为8080
将弹性云服务器添加到VPC通道:
建立API,认证类型选择APP
“请求Path”填“/stream”,“开启跨域”选项选择开启
建立API完成后,发布API到RELEASE环境。
建立APP并绑定API
在应用管理界面建立一个APP,并绑定刚刚建立的API。
建立OPTIONS方法的API
OPTIONS方法的API是提供给浏览器发送跨域请求的预请求使用,一样选择开启跨域(CORS),并将后端配置为Mock。
点完成建立API后,发布API到RELEASE环境。
建立网页,访问API
1.要访问APP认证方式的API,须要经过APP的key和secret生成签名,才能校验经过。生成签名使用下面连接下载的javascript SDK
https://console.huaweicloud.com/apig/?agencyId=c65a0db86e514fe298cdc57c6273411a®ion=cn-south-1&locale=zh-cn#/apig/manager/useapi/sdk
2.因为IE浏览器不支持Server Sent Event,须要从https://github.com/Yaffle/EventSource/下载浏览器兼容的Server Sent Event实现。
搜索并删除下面四行代码:
if (url.slice(0, 5) !== "data:" &&
url.slice(0, 5) !== "blob:") {
requestURL = url + (url.indexOf("?", 0) === -1 ? "?" : "&") + "lastEventId="+ encodeURIComponent(lastEventId);
}
3.建立index.html,内容以下:
<html>
<head>
<title>SSE APP test</title>
</head>
<body>
SSE APP test
<div id="a"></div>
<script src="js/eventsource.js"></script> 09 <script src="js/hmac-sha256.js"></script>
<script src="js/moment.min.js"></script>
<script src="js/moment-timezone-with-data.min.js"></script>
<script src="signer.js"></script>
<script>
var req = new signer.HttpRequest()
req.method = "GET"
req.host = "d3da6a917a844df3bd02896496b1b75b.apigw.cn-south-1.huaweicloud.com"
req.uri = "/stream"
var sig = new signer.Signer();
sig.AppKey = "<your app key>"
sig.AppSecret = "<your app secret>"
var opts = sig.Sign(req);
var source = new EventSourcePolyfill("http://d3da6a917a844df3bd02896496b1b75b.apigw.cn-south-1.huaweicloud.com" + req.uri, {
headers: opts.headers
});
source.onmessage = function (event) {
document.getElementById("a").innerHTML = event.data;
};
</script>
</body>
</html>
将刚刚建立的APP的AppKey和AppSecret填入上面指定位置。在本地用浏览器打开此页面,能够看到页面上显示的时间每秒刷新一次。
以上就是对如何实如今线聊天系统中的实时消息获取的详解,想要了解更多,点击这里当即体验一番吧~