在Spring websockets中发送错误消息

时间:2015-11-19 14:00:28

标签: spring stomp spring-websocket spring-messaging

我正在尝试使用STOMP通过SockJS在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

  

虽然用户目的地通常意味着经过身份验证的用户,但它   不是严格要求的。与之无关的WebSocket会话   经过身份验证的用户可以订阅用户目标。在   在这种情况下,@ SendToUser注释的行为与完全相同   with broadcast = false,即仅定位发送的会话   消息正在处理中。

当我从myHandler抛出此错误时,所有这一切都正常工作,这是我在websocket config中定义的Websocket Handler。

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

如果此拦截器有任何异常,我想将其抛回发送此消息的用户会话,

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使用什么作为用户名?

2 个答案:

答案 0 :(得分:6)

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

通过@SendToUsersimpMessagingTemplate.convertAndSendToUser()进行了几个小时的调试后,我意识到如果我们使用@SendToUser标头将自动设置,我们必须明确定义标头,如果我们使用{ {1}}。

simpMessagingTemplate.convertAndSendToUser()设置了两个标题

  

simpMessageType:SimpMessageType.MESSAGE,simpSessionId:的sessionId

所以我尝试添加标题

@SendToUser

它没有用,我尝试将标题设为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);

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); )。

SendToMethodReturnValueHandler.java

最后,

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

做了这个伎俩。

答案 1 :(得分:0)

  1. 仅当该用户订阅了目的地时才能使用convertAndSendToUser()

    super.convertAndSend(this.destinationPrefix + user + destination, payload, headers, postProcessor);
    
  2. user只能sessionId - headerAccessor.getSessionId()

  3. @MessageExceptionHandler只能使用@MessageMapping@SubscribeMapping完成工作。

  4. 有关详细信息,请参阅SendToMethodReturnValueHandler源代码。