WEB Message
WEB 通信
轮询
定时发送请求
- 优点:实现简单,无需做过多的更改
- 缺点:轮询的间隔过长,会导致用户不能及时接收到更新的数据;轮询的间隔过短,会导致查询请求过多,增加服务器端的负担
<div id="clock"></div>
<script>
let clockDiv = document.getElementById('clock');
setInterval(function(){
let xhr = new XMLHttpRequest;
xhr.open('GET','/clock',true);
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
console.log(xhr.responseText);
clockDiv.innerHTML = xhr.responseText;
}
}
xhr.send();
},1000);
</script>
后端服务
//轮询 服务端
let express = require("express");
let app = express();
app.use(express.static(__dirname));
app.get("/clock", function (req, res) {
res.end(new Date().toLocaleString());
});
app.listen(8080);
长轮询
长轮询是对轮询的改进版,客户端发送 HTTP 给服务器之后,看有没有新消息,如果没有新消息,就一直等待。当有新消息的时候,才会返回给客户端。在某种程度上减小了网络带宽和 CPU 利用率等问题。由于 http 数据包的头部数据量往往很大(通常有 400 多个字节),但是真正被服务器需要的数据却很少(有时只有 10 个字节左右),这样的数据包在网络上周期性的传输,难免对网络带宽是一种浪费。
- 优点:比 Polling 做了优化,有较好的时效性
- 缺点:保持连接会消耗资源; 服务器没有返回有效数据,程序超时。
<div id="clock"></div>
<script>
let clockDiv = document.getElementById('clock')
function send() {
let xhr = new XMLHttpRequest()
xhr.open('GET', '/clock', true)
xhr.timeout = 2000 // 超时时间,单位是毫秒
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
//如果返回成功了,则显示结果
clockDiv.innerHTML = xhr.responseText
}
send() //不管成功还是失败都会发下一次请求
}
}
xhr.ontimeout = function() {
send()
}
xhr.send()
}
send()
</script>
iframe
iframe 流方式是在页面中插入一个隐藏的 iframe,利用其 src 属性在服务器和客户端之间创建一条长连接,服务器向 iframe 传输数据(通常是 HTML,内有负责插入信息的 javascript),来实时更新页面。
- 优点:消息能够实时到达;浏览器兼容好
- 缺点:服务器维护一个长连接会增加开销;IE、chrome、Firefox 会显示加载没有完成,图标会不停旋转。
<body>
<div id="clock"></div>
<iframe src="/clock" style="display:none"></iframe>
</body>
//iframe流
let express = require("express");
let app = express();
app.use(express.static(__dirname));
app.get("/clock", function (req, res) {
setInterval(function () {
let date = new Date().toLocaleString();
res.write(`
<script type="text/javascript">
parent.document.getElementById('clock').innerHTML = "${date}";//改变父窗口dom元素
</script>
`);
}, 1000);
});
app.listen(8080);
SSE
全称 server sent event; 一般称为 EventSource; API。
EventSource 是服务器推送的一个网络事件接口。一个 EventSource 实例会对 HTTP 服务开启一个持久化的连接,以 text/event-stream 格式发送事件, 会一直保持开启直到被要求关闭。
一旦连接开启,来自服务端传入的消息会以事件的形式分发至你代码中。如果接收消息中有一个事件字段,触发的事件与事件字段的值相同。如果没有事件字段存在,则将触发通用事件。
数据信息被单向从服务端到客户端分发. 当不需要以消息形式将数据从客户端发送到服务器时,这使它们成为绝佳的选择。例如,对于处理社交媒体状态更新,新闻提要或将数据传递到客户端存储机制(如 IndexedDB 或 Web 存储)等等。
- 优点:消息能够实时到达;浏览器兼容好
- 缺点:消息单向
<div id="clock"></div>
<script>
// sse EventSource
var sseInfo = document.querySelector('#clock');
var evtSource = new EventSource('http://localhost:8080/clock');
//收到服务器发生的事件时触发
evtSource.onmessage = function (e) {
sseInfo.textContent = e.data + 'n';
}
//成功与服务器发生连接时触发
evtSource.onopen = function () {
console.log("Event source open!");
}
//出现错误时触发
evtSource.onerror = function (e) {
console.log("Event source error: " + e)
}
// 自定义事件
evtSource.addEventListener('myEvent', function (e) {
sseInfo.textContent = e.data + 'm';
});
evtSource.addEventListener('doClose', e => {
evtSource.close();
console.log("Event source closed!");
})
</script>
EventSource 规定字段
- event: 事件类型,如果指定了该字段,则在客户端接收到该条消息时,会在当前的 EventSource 对象上触发一个事件,事件类型就是该字段的字段值,你可以使用 addEventListener()方法在当前 EventSource 对象上监听任意类型的命名事件,如果该条消息没有 event 字段,则会触发 onmessage 属性上的事件处理函数。
- data: 消息的数据字段,如果该条消息包含多个 data 字段,则客户端会用换行符把它们连接成一个字符串来作为字段值。
- id: 事件 ID,会成为当前 EventSource 对象的内部属性"最后一个事件 ID"的属性值。
- retry: 一个整数值,指定了重新连接的时间(单位为毫秒),如果该字段值不是整数,则会被忽略。
WebSocket
WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议,它将 TCP 的 Socket(套接字)应用在了 webpage 上,使得通信双方建立一个保持活跃状态的连接通道。
WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
-
HTTP 的局限性
HTTP 是半双工协议,也就是说,在同一时刻数据只能单向流动,客户端向服务器发送请求(单向的),然后服务器响应请求(单向的)。
服务器不能主动推送数据给浏览器。这就会导致一些高级功能难以实现,诸如聊天室场景就没法实现。 -
WebSocket 的特点
支持双向通信,实时性更强
可以发送文本,也可以发送二进制数据
减少通信量:只要建立起 WebSocket 连接,就希望一直保持连接状态。和 HTTP 相比,不但每次连接时的总开销减少,而且由于 WebSocket 的首部信息很小,通信量也相应减少了
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?