背景
- 需要将后台发生的变化主动地、实时地传送到浏览器端,而不需要用户手动地刷新页面
- 例如:聊天室、实时的报价系统、在线游戏
- http 缺陷:通信只能由客户端发起
polling 轮询
轮询是客户端和服务器之间会一直进行连接,每隔一段时间就询问一次
- 浏览器实时显示服务器时间
<body>
<div>
时间:
</div>
<div class = "clock"></div>
<script>
function getTime() {
let xhr = new XMLHttpRequest()
xhr.open('get', '/polling')
xhr.onload = () => {
let content = xhr.response
let clock = document.querySelector('.clock')
clock.innerText = content
}
xhr.send()
}
getTime()
setInterval(getTime, 1000)
</script>
</body>
const Koa = require('koa')
const serve = require("koa-static");
const Router = require("koa-router");
// 时间格式化
const moment = require('moment')
const app = new Koa()
const router = new Router()
app.use(serve(__dirname + '/static'))
router.get('/polling', (ctx) => {
ctx.body = moment().format()
})
app.use(router.routes())
app.listen(8080, () => {
console.log('open 8080')
})


优点
实现简单,无需做过多的更改
缺点
- 轮询的间隔过长,会导致用户不能及时接收到更新的数据
- 轮询的间隔过短,会导致查询请求过多,增加服务器端的负担
SSE Server-Sent Events
实现原理
- 服务器向客户端声明,接下来要发送的是流信息
- 以流信息的方式,完成一次用时很长的下载
- 流信息
- 不属于一次性的数据包
- 是个数据流,需要连续不断地发送过来
- 客户端不会关闭连接,会一直等待
优点
- 使用 HTTP 协议,现有的服务器软件都支持
- 轻量级,使用简单
- 默认支持断线重连
- 支持自定义发送的消息类型
浏览器实时显示服务器时间

EventSource
developer.mozilla.org/zh-CN/docs/…
<body>
时间 sse
<div class="block"></div>
<script>
// 共用一个地址 & ip 前面的地址不用写
const eventSource = new EventSource("/sse");
eventSource.addEventListener("open", (e) => {
console.log("open");
console.log(e);
});
eventSource.addEventListener("message", (e) => {
console.log("message");
console.log(e);
document.querySelector('.block').innerText = e.data
});
eventSource.addEventListener("sock", (e) => {
console.log("sock");
console.log(e);
document.querySelector('.block').innerText = e.data
});
eventSource.addEventListener("error", (e) => {
console.log("error");
console.log(e);
});
</script>
</body>
const http = require("http");
const fs = require("fs");
const moment = require("moment");
const server = http.createServer((req, res) => {
// fs
// 接口 sse
if (req.url === "/sse") {
// 必须设置成 event-stream 流信息
res.setHeader("content-type", "text/event-stream");
// 固定格式 data: xxxxx\n\n
setInterval(() => {
// 指定触发哪个东西
res.write("event: sock\n")
// 两个 \n 表示这条数据已经结束了,上下两行是一条数据
res.write(`data: ${getDate()}\n\n`);
}, 1000);
// 一定不要写 end
// sse
} else {
// 静态服务
const readStream = fs.createReadStream("./static/index.html");
readStream.pipe(res);
}
});
function getDate() {
return moment().format("MMMM Do YYYY, h:mm:ss a");
}
server.listen(3000);
websocket
特点
- 双工通信
- 允许跨域
- 建立在 TCP 协议之上
- 建立持久连接, 只需要一次 http 握手
- 数据格式比较轻量,性能开销小,通信高效
- 可以发文本,也可以发二进制数据
- 没有同源限制
- 协议标识符是 ws
缺点
- 兼容性问题
协议升级
