spring - 在 Spring websocket 中发送错误消息

标签 spring stomp spring-websocket spring-messaging

我正在尝试通过 SockJS 使用 STOMP 在 Spring websockets 中发送错误消息。

我基本上正在努力实现正在完成的任务 here .

这是我的异常处理程序

@MessageExceptionHandler
@SendToUser(value = "/queue/error",broadcast = false)
public ApplicationError handleException(Exception message) throws ApplicationError {
        return  new ApplicationError("test");
}

我正在订阅

stompClient.subscribe('/user/queue/error', stompErrorCallback, {token: accessToken});

在我的例子中,用户未经过身份验证,但来自 here

While user destinations generally imply an authenticated user, it isn’t required strictly. A WebSocket session that is not associated with an authenticated user can subscribe to a user destination. In such cases the @SendToUser annotation will behave exactly the same as with broadcast=false, i.e. targeting only the session that sent the message being handled.

当我从 myHandler 抛出此错误时,所有这些工作正常,这是我在 websocket 配置中定义的 Websocket 处理程序。

我有一个ClientInboundChannelInterceptor,它扩展了ChannelInterceptorAdapter,它拦截preSend中的所有消息。

如果此拦截器出现任何异常,我想将其扔回发送此消息的用户 session ,

public class ClientInboundChannelInterceptor extends ChannelInterceptorAdapter {
    @Autowired
    @Lazy(value = true)
    @Qualifier("brokerMessagingTemplate")
    private SimpMessagingTemplate simpMessagingTemplate;

    @Override
    public Message<?> preSend(Message message, MessageChannel channel) throws IllegalArgumentException{
         if(some thing goes wrong)
           throw new RuntimeException();
    }

    @MessageExceptionHandler
    @SendToUser(value = "/queue/error",broadcast = false)
    public ApplicationError handleException(RuntimeException message) throws    ApplicationError {
        return  new ApplicationError("test");
    }
}

@MessageExceptionHandler 不会捕获此异常。所以我尝试使用 simpMessagingTemplate 直接将其发送给用户。

我基本上想做:

simpMessagingTemplate.convertAndSendToUser(SOMETHING,"/queue/error",e);

SOMETHING 应该是正确的用户名,但在我的情况下用户未经过身份验证,因此我无法使用 headerAccessor.getUser().getName()

我什至尝试过

simpMessagingTemplate.convertAndSendToUser(headerAccessor.getHeader("","/queue/error",e, Collections.singletonMap(SimpMessageHeaderAccessor.SESSION_ID_HEADER, headerAccessor.getSessionId()));

但这不起作用。

我什至尝试过 headerAccessor.getSessionId() 来代替用户名,但这似乎不起作用。

正确的做法是什么?

我应该在 convertAndSendToUser 中使用什么作为用户名?

最佳答案

我最初的直觉是正确的,在未经身份验证的用户情况下,sessionId 被用作用户名,但问题出在 header 上。

通过 @SendToUsersimpMessagingTemplate.convertAndSendToUser() 调试几个小时后,我意识到如果我们使用 @SendToUser header 将会自动设置,如果我们使用 simpMessagingTemplate.convertAndSendToUser(),则必须显式定义 header 。

@SendToUser 正在设置两个 header ,

simpMessageType:SimpMessageType.MESSAGE,simpSessionId:sessionId

所以我尝试添加标题,

String sessionId = headerAccessor.getSessionId();
Map<String,Object> headerMap = new HashMap<>();
headerMap.put("simpMessageType", SimpMessageType.MESSAGE);
headerMap.put("simpSessionId",sessionId);   
simpMessagingTemplate.convertAndSendToUser(headerAccessor.getSessionId(),"/queue/error",e,headerMap);

它不起作用,我尝试将 header 指定为 MessageHeaders

String sessionId = headerAccessor.getSessionId();
Map<String,Object> headerMap = new HashMap<>();
headerMap.put("simpMessageType", SimpMessageType.MESSAGE);
headerMap.put("simpSessionId",sessionId); 
MessageHeaders headers = new MessageHeaders(headerMap);

simpMessagingTemplate.convertAndSendToUser(headerAccessor.getSessionId(),"/queue/error",e,headers);

也没用。

经过更多调试后,我找到了设置 header 的正确方法,并且可能这是创建这些 header 的唯一方法(来自 SendToMethodReturnValueHandler.java)。

private MessageHeaders createHeaders(String sessionId) {
    SimpMessageHeaderAccessor headerAccessor = SimpMessageHeaderAccessor.create(SimpMessageType.MESSAGE);
    headerAccessor.setSessionId(sessionId);
    headerAccessor.setLeaveMutable(true);
    return headerAccessor.getMessageHeaders();
}

最后,

String sessionId = headerAccessor.getSessionId();
template.convertAndSendToUser(sessionId,"/queue/error","tesssssts",createHeaders(sessionId));

成功了。

关于spring - 在 Spring websocket 中发送错误消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33806014/

相关文章:

java - Spring - 获取拦截器/过滤器中给定请求的方法

java - Spring MVC + Oracle LOB + 流式处理

Spring Data Rest 可分页子集合

websocket - 如何在 Cypress.io 中等待 WebSocket STOMP 消息

http - 为什么 HTTP 不是消息传递协议(protocol)? (根据 RabbitMQ)

spring-mvc - 如何在 Spring MVC 中正确配置 Stomp 和 SockJS 端点?

java - Spring Boot 如何知道 Heroku 的 DATABASE_URL 配置变量?

spring - WebSocketConfigurer 和 @Scheduled() 在应用程序中不能很好地工作

spring - 使用 STOMP 订阅主题 Spring WebSocket 时未创建动态队列?

java - Websocket 跟踪 Spring 中的连接