在 HTTP/1.1 及以前的版本里,客户端、服务端之间的通讯模式只支持一种请求-响应模式,这是一种半双工通讯模式。 而且,在这个模型中,服务端是“被动方”,只能响应用户的请求,不能主动地推送消息给客户端。 为了解决这个问题,出现了支持实时通讯的 WebSocket 协议,以及 HTTP/2、HTTP/3 中的 Stream、Server Push 等特性。 但是,在 HTTP/1.1 版本中,要实现“实时通讯”的效果只能通过轮询(Polling)技术。而且,轮询也只能达到近似“实时通讯”效果。
今天,我将介绍如何在 Spring Boot 中通过轮询实现服务端数据变动后通知客户端。
01-短轮询和长轮询
短轮询比较好理解,指在客户端通过循环的方式每隔一段时间就请求一下服务端,是否有数据更新。 短轮询的伪代码类似于:
while(true) {
// 请求服务端
resposne = query(request);
// 如果服务端有数据返回,则处理;否则,继续请求服务端
if (hasData(response)) {
process(response);
} else {
// 隔 100ms 再次请求
sleep(100);
}
}
复制代码
短轮询方案中最大的问题是,频繁的请求对服务端的压力太大,而且也浪费网络带宽资源。 长轮询是对短轮询方案的一种改进,旨在减少对服务器资源的浪费。 长轮询在中间件中使用比较常见,例如 Nacos 配置中心,RocketMQ 消息队列等。
长轮询与短轮询的机制是类似的,客户端的逻辑不变,主要在服务端优化。 在长轮询中,服务端在没有数据更新时并不会立即响应客户端的请求,而是会 hold 住一段时间。 在这段时间中,如果数据有更新,则立即返回;如果没有更新,超时后客户端会再次发起请求。
01.1-阻塞长轮询实现方式
一种标准的实现方式是,在服务端直接等待数据更新,等待一段时间后再响应请求。
@RestController
@RequestMapping("/polling")
public class BlockingController {
@GetMapping("/blocking")
public ResponseEntity<?&g