You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SockJsClient(React) WebSocket握手成功后onMessage未触发,消息接收异常

问题根因及修复方案

核心根因

1. 推送路径与订阅路径不匹配

Spring Stomp 的convertAndSendToUser方法默认会自动在推送路径前拼接/user/{用户名}前缀,你当前服务端实际推送的完整路径为:
/user/{pushToken}/ws-push-notification/item/{pushToken}
但前端订阅的路径为ws-push-notification/item/{pushToken},二者完全不匹配,因此无法触发回调。

2. 路径格式不符合规范

STOMP 协议的订阅路径默认需要以斜杠/开头,你前端定义的 topic 缺少开头的斜杠。

3. 身份映射逻辑错误

convertAndSendToUser的第一个参数是 Spring Security 认证上下文中的用户名,不是 SessionId,你直接传入 pushToken 作为用户名,需要确保项目的 WebSocket 认证逻辑已经将 pushToken 映射为当前连接的用户 Principal 名称。


具体修复步骤

  • 方案一:调整前端订阅路径,补全前缀即可
// 修改前
const topic = "ws-push-notification/item/" + props.pushToken;
// 修改后
const topic = "/user/ws-push-notification/item/" + props.pushToken;
  • 方案二:改用路径直接推送,避免用户身份映射逻辑,修改服务端推送代码
public void pushNotification(String pushToken, PushNotificationDto notificationDto) {
    // 直接按完整路径推送,不需要额外处理用户和session头
    template.convertAndSend("/ws-push-notification/item/" + pushToken, notificationDto);
}

对应前端订阅路径修改为:

const topic = "/ws-push-notification/item/" + props.pushToken;
  • 方案三:保留convertAndSendToUser用法的适配方案
    需要配置 WebSocket 握手拦截器,在连接建立阶段将 pushToken 设置为当前连接的 Principal:
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
    registry.addEndpoint("/ws-push-notifications")
            .setAllowedOrigins(allowedOrigin)
            // 添加握手拦截器设置Principal
            .addInterceptors(new HandshakeInterceptor() {
                @Override
                public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
                    // 从请求参数或者header中获取pushToken设置为Principal
                    String pushToken = request.getHeaders().getFirst("push-token");
                    if (pushToken != null) {
                        attributes.put("principal", () -> pushToken);
                    }
                    return true;
                }
                @Override
                public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {
                }
            })
            .withSockJS();
}

内容的提问来源于stack exchange,提问作者huseyinkadioglu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 03:09:02