问题来源
在项目中,需要实时获取到是否有新通知,因为这个需求比希望尽量少的请求服务端,减少服务端压力
了解到可以使用长连接,于是按照得到了一下实现(前端):
getNews() {
getNewNum().then((res) => {
if (res.code === 200) {
this.unreadMessageCount = res.news
this.longPolling();
}
}).catch(error => {
console.error('消息异常:',error);
this.longPolling();
});
},
longPolling() {
setTimeout(() => {
this.getNews();
}, 10000);
},
后来仔细想,这并不是长链接,长连接是第一次连接后后端会不断请求查看数据库有没有新消息,如果有就返回,再去断开连接
实验
经过抓包发现每次(10s)请求的原端口不一致,即不是同一个 TCP 连接
目前是轮询实现,这不是长连接,长连接是 TCP 连接不断开,有数据才会返回,而 HTTP 协议是无状态协议,收到请求后立刻响应,并断开连接,使用 HTTP 发出的请求都是短连接
于是想起来当时想要实现长连接,但是最终用轮询的方式实现的
那么如何实现长连接呢?
可以使用 WebSocket 全双工通信协议,可以实习长连接,主要应用于在线聊天室等
我的项目使用的是axios, 能实现长连接吗?
不行,Axios 是一个基于 promise 的 HTTP 库。上面说的使用 HTTP 发出的请求都是短连接,在使用FastAPI处理请求也可以知道没有办法将请求挂起,必须要有返回也就是响应
问题得到解答于是了解了下即使通信
即时通信技术
即时通讯的应用场景就是需要实时通信的场景,如在线聊天室
四种方式
轮询、长轮询(comet)、长连接(SSE)、WebSocket
它们大体可以分为两类,一种是在HTTP基础上实现的,包括短轮询、长轮询和长连接;另一种不是在HTTP基础上实现是,即WebSocket。下面分别对其进行简单的介绍。
轮询
前端(客户端)发起定时器的循环请求后台,后台(服务端)接到请求后返回响应信息的一种方式
适用于:适用于小型应用,或者同时在线人数较少的应用
优点:简单省时,后端程序编写比较容易(几乎不用做什么特殊处理)
缺点:不及时(得看定时器的间隔),消耗大 ( 服务器宽带和资源)
长轮询(comet)
上面轮询每发出一次请求就要新建一个Http请求,长轮询只启动一个HTTP请求,其连接的服务端会挂起此次连接,后端定时器去查询数据库有没有新消息(特点就是重点在后端处理),直到有新消息才返回响应信息,客户端处理完响应信息后再向服务器发送新的Http请求,以此类推。区别于轮询的就是没有新消息就不会发送新的请求
通俗理解就是把前端的定时器转移到了后端,但是能及时拿到结果
后端代码具体的不做详细介绍原理如下:后端写sleep(秒) 睡眠挂起请求,就是把前端的定时器移动到了后端,后端while循环,不停的问数据库有没有结果。没有进入定时睡眠,有则跳出循环处理逻辑。
前端核心就是循环调用ajax(递归)
// 获取最新的投票结果
function get_vote() {
axios.request({
url: '/get_vote',
method: 'get'
}).then(function (response) {
// 判断后端的数据是否为空
if (response.data != '') {
// 获取到最新的数据do somethings
}
// 获取完数据后,再发送请求,看还有没有新数据生成
get_vote()
});
}
适用于:适用于小型应用,或者同时在线人数较少的应用
优点:可实现实时数据回传,长轮询和轮询比起来,明显减少了很多不必要的http请求次数,相比之下节约了资源
缺点:连接挂起也会导致资源的浪费(服务器压力大,频繁操作询问数据库有没有新结果)
长连接(SSE)
SSE是HTML5新增的功能,SSE(sever-sent events)服务器端推送事件,是指服务器推送数据给客户端,而不是传统的请求响应模式。简单的说,就是浏览器向服务器发送一个HTTP请求,然后服务器不断单向地向浏览器推送“信息”。而SSE最大的特点就是可以实现只要服务器端数据有更新,就可以马上发送到客户端
优点:SSE和轮询,长轮询相比它不用处理很多请求,不用每次建立新连接,延迟较低;SSE和WebSocket相比,最大的优势是便利,服务端不需要其他的类库,开发难度较低。
缺点:如果客户端有很多,那就要保持很多长连接浏览器一直转圈,这会占用服务器大量内存和连接数
WebSocket
websocket 最大的特点就是可以双向通信。这里可以使用 ws.send() 方法发送数据, 不过只能发送String和二进制. 这里,我们通常call 数据叫做 Frames. 他是数据发送的最小单元.包含数据的长度和数据内容
优点:WebSocket 协议在2008年诞生,2011年成为国际标准。所有浏览器都已经支持了。可以双向通信
缺点:需要前后端全都换上新的协议支持,WebSocket 技术也比较复杂, 成本比较高,后台开发工期大约需要一周
综合成本和时间简单项目用轮询,复杂的要求性能的用websocket