zoukankan      html  css  js  c++  java
  • 详解如何实现在线聊天系统中的实时消息获取

    序言

    传统web浏览器应用采用客户端主动请求方式,只有在收到浏览器请求时服务端才返回消息,这种模式已经不能满足日益多样化的web应用需求,例如:

    在线聊天系统:需要实时获取聊天消息。

    实时监控系统:需要实时获取监控对象状态。如仪表读数、告警信息等。

    随着html技术演进,发展出了多种服务器推送技术,用于服务器向浏览器客户端推送消息。

    Ajax轮询

    采用Ajax定时向服务端发送请求检查有无消息更新。网页定时向服务器发送请求,若服务器有消息推送,则返回消息,否则返回空消息,如下图所示:

    这种轮询方式需要发送大量无效请求,大大消耗了服务器资源,且推送消息的实时性较低。

    Ajax长轮询

    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()) + " ");    

     interval = setInterval(function () {    

    res.write("data: " + (new Date()) + " ");  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&region=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填入上面指定位置。在本地用浏览器打开此页面,可以看到页面上显示的时间每秒刷新一次。

    以上就是对如何实现在线聊天系统中的实时消息获取的详解,想要了解更多,点击这里立即体验一番吧~

  • 相关阅读:
    GIS 空间分析案例教程-坐标高斯投影正反算
    GIS 空间分析案例分析-错误排除经验总结
    第一个Json.Net Demo
    点到折线最短距离所在点距离折线起点的累积距离
    使用Proj.Net创建空间参考
    C#通过存储过程进行查询
    分幅输出影像瓦片
    ArcEngine和GDAL读写栅格数据机制对比(二)—— IPixelBlock读写栅格
    Web开发学习
    [3D]绘制XYZ小坐标轴
  • 原文地址:https://www.cnblogs.com/middleware/p/9439382.html
Copyright © 2011-2022 走看看