Mliraitowa 2025-07-31 19:22 采纳率: 0%
浏览 15

spring-boot-starter-websocket + stompjs + sockjs-client

以下是在开发中遇见的问题:为什么 WebSocket 连接成功了之后,无法收到服务端发来的默认客服消息。也设置了header请求头,服务端也能解析出UserId并设置到 accessor.setUser(new StompPrincipal(userId)); 在 WebSocketConnectListener 连接监听方法里面也能打印出用户也登录和用户ID,但未正常推送消息到客户端的


```javascript
 this.stompClient.subscribe('/user/queue/messages', msg => {
            if (msg.body) {
              const message = JSON.parse(msg.body);
              this.messages.push(message);
            }
          });

的这个方法里,无法再页面上显示默认消息

```java

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws/chat")
                .setAllowedOriginPatterns("http://172.16.32.4:8082", "http://172.16.32.4:8080")
                .withSockJS();
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.enableSimpleBroker("/topic", "/queue");
        registry.setApplicationDestinationPrefixes("/app");
    }

    @Override
    public void configureClientInboundChannel(ChannelRegistration registration) {
        registration.interceptors(new ChannelInterceptor() {
            @Override
            public Message<?> preSend(Message<?> message, MessageChannel channel) {
                StompHeaderAccessor accessor = StompHeaderAccessor.wrap(message);
                if (StompCommand.CONNECT.equals(accessor.getCommand())) {
                    try {
                        String Authorization = accessor.getFirstNativeHeader("Authorization");
                        if (Authorization == null || Authorization.isEmpty()) {
                            throw new MessageDeliveryException("会话已超时,请先登录再继续咨询。");
                        }
                        String userId = AuthToUserIdUtils.getUserIdFromStomp(Authorization);
                        accessor.setUser(new StompPrincipal(userId));
                        return MessageBuilder.createMessage(message.getPayload(), accessor.getMessageHeaders());
                    } catch (Exception e) {
                        throw new MessageDeliveryException("会话已超时,请先登录再继续咨询。");
                    }
                }
                return message;
            }
        });
    }
}

```java
@Component
public class WebSocketConnectListener implements ApplicationListener<SessionConnectedEvent> {

    @Autowired
    private SimpMessagingTemplate messagingTemplate;

    @Autowired
    private ChatSessionService chatSessionService;

    @Autowired
    private ChatMessageService chatMessageService;
    @Override
    public void onApplicationEvent(SessionConnectedEvent event) {
        StompHeaderAccessor accessor = StompHeaderAccessor.wrap(event.getMessage());
        Principal userPrincipal = accessor.getUser();
        if (userPrincipal != null) {
            System.out.println("用户已登录");
            System.out.println("用户ID:" + userPrincipal.getName());
            String userId = userPrincipal.getName();
            // 1. 检查是否已有会话
            ChatSession session = chatSessionService.getOrCreateSessionForUser(userId);
            // 2. 构造系统欢迎消息
            ChatMessage welcomeMsg = new ChatMessage();
            welcomeMsg.setSessionId(session.getId());
            welcomeMsg.setSenderRole("system");
            welcomeMsg.setSenderId(Integer.valueOf(userId));
            welcomeMsg.setMessageType("system");
            welcomeMsg.setContent("您好,欢迎来到客服中心,我们会尽快为您服务!");
            welcomeMsg.setCreatedAt(LocalDateTime.now());

            // 3. 存入数据库
//            chatMessageService.save(welcomeMsg);

            // 4. 发送消息给用户
            HashMap<String, Object> message = new HashMap<>();
            message.put("text", "您好,欢迎来到客服中心,我们会尽快为您服务!");
            message.put("isUser", false);
            message.put("avatar", "http://localhost:8081/upload/cbdbbfe6c2d9408f8242c10a674affea1753843824516.jpg");
            message.put("time", LocalDateTime.now());

            new Timer().schedule(new TimerTask() {
                @Override
                public void run(){
                    messagingTemplate.convertAndSendToUser(userId, "/queue/messages", message);
                }
            },1500);
        }else {
            System.out.println("用户未登录");
        }
    }
}


connect() {
      this.stompClient = new Client({
        webSocketFactory: () => new SockJS('http://172.16.32.4:8081/ws/chat'),
        reconnectDelay: 5000,
        connectHeaders: { 'Authorization': 'Bearer ' + localStorage.getItem("token")},
        onConnect: () => {
          this.hasErrorShown = false;

          this.stompClient.subscribe('/user/queue/messages', msg => {
            if (msg.body) {
              const message = JSON.parse(msg.body);
              this.messages.push(message);
            }
          });
        },
        onStompError: (frame) => {
          if (!this.hasErrorShown) {
            const errorMsg = frame.headers['message'];
            this.$message.error(errorMsg);
            this.hasErrorShown = true;
          }
        }
      });
      this.stompClient.activate();
    },

```

  • 写回答

4条回答 默认 最新

  • u013132758 新星创作者: 人工智能技术领域 2025-07-31 19:43
    关注

    让 “紫雾凌寒” 来帮你回答,本回答结合 DeepSeek

    如果还有问题,请评论或点击头像私信,如果有帮助到您, 请关注、采纳、点赞

    1. 关键点分析
      - 连接成功但收不到服务端默认客服消息,这可能涉及到消息发送、订阅以及消息处理流程的问题。
      - 设置了header请求头且服务端能解析出UserId,说明连接建立时的部分信息传递是正常的,但后续消息交互存在异常。
    2. 解决方案
      - 前端代码检查
      • 确保订阅的目的地正确。例如,在使用stompjs时,订阅代码可能类似这样:
        javascript const socket = new SockJS('/websocket-endpoint'); const stompClient = Stomp.over(socket); stompClient.connect({}, function (frame) { console.log('Connected: ', frame); stompClient.subscribe('/topic/defaultMessage', function (message) { console.log('Received: ', message.body); }); }, function (error) { console.log('Connection error: ', error); });
      • 检查是否正确处理了连接成功和失败的回调。如果连接成功回调中订阅代码没有正确执行,就无法接收消息。
      • 服务端代码检查
      • 确认服务端发送消息到/topic/defaultMessage这个目的地的逻辑是否正确。例如在Spring Boot中,使用@MessageMapping注解来处理消息发送,类似这样:
        java @MessageMapping("/defaultMessage") @SendTo("/topic/defaultMessage") public String sendDefaultMessage() { return "这是默认客服消息"; }
      • 检查服务端的消息发送是否考虑了前端设置的header。如果服务端在发送消息时需要根据header中的UserId进行一些特殊处理,确保相关逻辑正确实现。
      • 网络和配置检查
      • 检查WebSocket连接的网络配置,确保没有防火墙等限制阻止消息的正常传输。
      • 查看Spring Boot应用中关于WebSocket和STOMP的配置是否正确,例如WebSocket的端口配置等。
    3. 多种解决方案的优缺点
      - 前端代码检查
      • 优点:相对容易定位前端在消息接收流程中的问题,直接检查订阅代码和连接回调逻辑。
      • 缺点:如果问题出在服务端,可能无法发现深层次原因。
      • 服务端代码检查
      • 优点:能全面排查服务端消息发送、处理以及与前端交互的整个流程。
      • 缺点:需要熟悉服务端代码逻辑,排查范围相对较广。
      • 网络和配置检查
      • 优点:能从基础环境层面排除问题,避免因网络或配置问题导致消息无法正常传输。
      • 缺点:比较基础,可能无法直接定位到具体的业务代码问题。
    4. 总结
      首先要分别从前端和服务端代码以及网络配置等方面进行全面检查。前端重点检查订阅逻辑和连接回调,服务端检查消息发送处理逻辑以及与前端交互部分,同时确保网络和相关配置正确,这样才能准确找出无法收到服务端默认客服消息的原因并解决问题。

    希望以上解答对您有所帮助。如果您有任何疑问,欢迎在评论区提出。

    评论

报告相同问题?

问题事件

  • 创建了问题 7月31日