Skip to content
特性SSE轮询WebSocket
通讯方向服务器向客户端推送数据客户端定时请求服务器获取数据客户端与服务器双向通讯
连接类型长连接:使用 HTTP/1.1 或 HTTP/2 长连接短连接:每次请求都是独立的 HTTP 请求长连接:通过 TCP 建立的持久连接
传输协议HTTP/1.1 或 HTTP/2HTTPTCP
浏览器支持广泛支持(HTML5 原生支持)全面支持,所有浏览器均支持广泛支持(需通过 WebSocket API 实现)
消息发送频率服务器可随时推送数据客户端主动定时请求,频率取决于客户端设置实时、即时双向发送
服务器开销较低:只需保持一个长连接高:每次请求都需要重新建立 HTTP 连接较高:需保持 TCP 连接,管理心跳包
客户端开销低:只需处理服务器推送的数据高:每次请求都会产生额外的资源消耗中等:需保持与服务器的连接
传输数据格式纯文本、JSON 等纯文本、JSON 等任意格式(二进制、文本等)
连接恢复机制自动恢复:连接中断时,客户端会自动重新连接无自动恢复,需客户端重新发起请求需开发者自行实现重连机制
适用场景适合实时数据推送、通知、监控等单向通讯场景适用于低频率、对实时性要求不高的场景适合即时通讯、协作应用等双向通讯场景
复杂度简单:实现轻量且代码量少简单:代码量少,但性能较差复杂:需处理更多逻辑,如握手、心跳等
实时性高:服务器可立即推送消息低:依赖客户端的请求频率高:双向即时通讯
防火墙/代理兼容性高:使用标准 HTTP 协议,通常无额外配置需求高:使用标准 HTTP 协议可能较低:需配置防火墙或代理来允许 TCP 连接
带宽消耗较低:保持长连接,但只在有数据时传输较高:每次轮询都会消耗资源和带宽较低:保持长连接,数据按需传输

轮询

SSE

WebSocket

xml
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

方法概念

  • WebSocketSession:表示当前 WebSocket 会话,通过它可以访问当前连接的信息,例如会话 ID、客户端信息等
    • 如果前端断开了连接,sendMessage 发送消息时,会抛出 IOException
  • TextWebSocketHandler
    • afterConnectionEstablished 在 WebSocket 连接成功后被调用
    • afterConnectionClosed 在 WebSocket 连接关闭后被调用
    • handleTransportError 当 WebSocket 连接发生传输错误时被调用
    • handleTextMessage 当接收到客户端发送的文本消息时,调用此方法进行处理。可以在这里解析消息、执行操作,并且可以通过 session 对象回复消息给客户端

实战

  • 注册访问端点
java
/**
 * WebSocket 配置类
 */
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    private @Resource ImageProcessingArchivesHandler imageProcessingArchivesHandler;
    private @Resource ImageProcessingArchivesFilesHandler imageProcessingArchivesFilesHandler;

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        // 注册 WebSocket 处理器,添加访问路径和可访问的源
        registry.addHandler(imageProcessingArchivesHandler, "/imageProcessingArchives").setAllowedOrigins("*");
        registry.addHandler(imageProcessingArchivesFilesHandler, "/imageProcessingArchiveFiles").setAllowedOrigins("*");
    }

}
  • 处理器
java
/**
 * 图像处理进度 Handler - 案卷级
 */
@Component
@RequiredArgsConstructor
public class ImageProcessingArchivesHandler extends TextWebSocketHandler {

    private final ObjectMapper objectMapper;
    private final IImageProcessingService imageProcessingService;
    private final VolFilesMapper volFilesMapper;

    @Override
    public void afterConnectionEstablished(WebSocketSession session) {
        try {
            System.out.println("WebSocket 连接成功!");
        } catch (Exception e) {
            log.error("WebSocket 错误:" + e.getMessage());
        }
    }

    @Override
    public void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        int processedImages = 0;
        int totalImages = scannedFiles.size();
        while (true) {
            if (processedImages > totalImages) {
                session.close(CloseStatus.NORMAL);  // 关闭 WebSocket 连接
                break;
            }

            ObjectNode objectNode = objectMapper.createObjectNode()
                    .put("processedImages", processedImages)
                    .put("totalImages", totalImages);
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(objectNode)));
            Thread.sleep(1000); // 每秒发送一次进度

            processedImages++;
        }
    }

}
  • 前端访问 :ws://localhost:8060/imageProcessingArchives

状态码

  • 报错 1006 连接被关闭 : Spring Security 默认会拦截所有请求,包括 WebSocket 的握手请求。因此,需要在 Spring Security 配置中明确允许 WebSocket 请求通过