在Spring WebSockets中发送错误消息 [英] Sending Error message in Spring websockets

查看:310
本文介绍了在Spring WebSockets中发送错误消息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试通过SockJS在带有STOMP的Spring Websocket中发送错误消息.

I am trying to send error messages in Spring websockets with STOMP over SockJS.

我基本上是在尝试实现

I am basically trying to achieve which is being done 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});

在我的情况下,用户未通过身份验证,但来自

User in my case is not authenticated, but from here

虽然用户目的地通常暗指经过身份验证的用户,但它 并非严格要求.未关联的WebSocket会话 经过身份验证的用户可以订阅用户目的地.在 在这种情况下,@ SendToUser批注的行为与 使用broadcast = false,即仅定位发送该会话的会话 邮件正在处理.

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处理程序.

All this works fine when I am throwing this error from myHandler which is my Websocket Handler defined in websocket config.

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

I have a ClientInboundChannelInterceptor which extends ChannelInterceptorAdapter which intercepts all the messages in preSend.

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

In case of any exception in this interceptor, I want to throw it back to the user session which sent this message,

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直接将其发送给用户.

@MessageExceptionHandler does not catch this exception. So I tried sending it to the user directly using simpMessagingTemplate.

我基本上想做:

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

某些内容应该是正确的用户名,但在我的情况下用户未通过身份验证,因此我不能使用headerAccessor.getUser().getName()

SOMETHING should be the correct username but user is not authenticated in my case, so I can't use headerAccessor.getUser().getName()

我什至尝试过

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

但这不起作用.

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

I have even tried headerAccessor.getSessionId() in the place of username, but that does not seem to work.

正确的方法是什么?

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

What should I use as username in convertAndSendToUser?

推荐答案

我的最初直觉是正确的,在未经身份验证的用户情况下,使用sessionId作为用户名,但是问题出在头文件上.

My initial intuition was correct, sessionId is used as the username in case of unauthenticated user situations, but the problem was with headers.

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

After few hours of debugging through @SendToUser and simpMessagingTemplate.convertAndSendToUser(), I realised that if we use @SendToUser headers will be set automatically and we have to explicitly define the headers if we are using simpMessagingTemplate.convertAndSendToUser().

@SendToUser正在设置两个标题,

simpMessageType:SimpMessageType.MESSAGE,simpSessionId:sessionId

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

它不起作用,我尝试将标题设为MessageHeaders

It did not work, I have tried giving the headers as 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).

After some more debugging I found out the correct way to set the headers, and probably this is the only way to create these headers(from 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 WebSockets中发送错误消息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆