问题描述
我正在尝试通过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
当我从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.
在通过@SendToUser
和simpMessagingTemplate.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
正在设置两个标题,
所以我尝试添加标题,
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中发送错误消息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!