在Spring WebSocket中发送错误消息

在Spring WebSocket中发送错误消息,spring,stomp,spring-websocket,spring-messaging,Spring,Stomp,Spring Websocket,Spring Messaging,我正在尝试用STOMP over SockJS在Spring WebSocket中发送错误消息 我基本上是在努力实现正在实现的目标 这是我的异常处理程序 @MessageExceptionHandler @SendToUser(value = "/queue/error",broadcast = false) public ApplicationError handleException(Exception message) throws ApplicationError { r

我正在尝试用STOMP over SockJS在Spring WebSocket中发送错误消息

我基本上是在努力实现正在实现的目标

这是我的异常处理程序

@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});
本例中的用户未通过身份验证,而是来自

虽然用户目的地通常意味着经过身份验证的用户,但是 没有严格要求。未关联的WebSocket会话 通过身份验证,用户可以订阅用户目的地。在里面 在这种情况下,@SendToUser注释的行为与 使用broadcast=false,即仅针对发送消息的会话 正在处理的消息

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

我有一个
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");
    }
}
SOMETHING应该是正确的用户名,但在我的例子中,用户没有经过身份验证,因此我不能使用
headerAccessor.getUser().getName()

我甚至试过用它

simpMessagingTemplate.convertAndSendToUser(headerAccessor.getHeader("","/queue/error",e, Collections.singletonMap(SimpMessageHeaderAccessor.SESSION_ID_HEADER, headerAccessor.getSessionId()));
但这是行不通的

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

正确的方法是什么

convertandtouser
中,我应该使用什么作为用户名

  • 仅当该用户已订阅目标时,才能使用
    convertAndSendToUser()

    super.convertAndSend(this.destinationPrefix + user + destination, payload, headers, postProcessor);
    
  • 其中,
    user
    可以只是
    sessionId
    -
    headerAccessor.getSessionId()

  • @MessageExceptionHandler
    仅使用
    @MessageMapping
    @SubscribeMapping
    执行其工作


  • 有关更多信息,请参见
    SendToMethodReturnValueHandler
    源代码。

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

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

    @SendToUser
    正在设置两个标题

    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);
    
    也不管用

    在进一步调试之后,我找到了设置头的正确方法,这可能是创建这些头的唯一方法(从
    SendToMethodReturnValueHandler.java

    所以最后,

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

    我不知道你为什么说我们不能使用
    convertAndSendToUser()
    ,但是用正确的方式设置标题是有效的。哦!很抱歉是的,我的意思是“你可以”。我想说的是,您不能从拦截器中使用“@MessageExceptionHandler”,因为现在太早了。看我的#3@Tobia很高兴它有帮助:)这项工作,谢谢。更多细节:使用SpringFramework 4.3.2。我的客户端是Stomp.js Websocket,而不是Stomp。您需要要发送消息的其他用户的simpSessionId。我的客户端:stompClient.subscribe('/user/queue/bancaria.readcard',function(messageOutput)…和服务器:messagingTemplate.convertAndSendToUser(targetSessionId,“/queue/bancaria.readcard”,message,headers);我现在不使用Spring安全性。谢谢。
    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);
    
    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));