我有一个简单的Spring应用程序,具有WebSocket功能,到目前为止一切都运行正常。现在我想使用@SendToUser注释从服务器向特定客户端发送消息。但是这会导致错误“忽略消息,没有可用的主体信息”。我理解我在服务器上没有任何登录信息,因此每个用户都是“匿名”的,并且没有主体(暂时不使用Spring Security)。但是每个用户都有一个会话ID。难道不能使用会话ID来区分用户吗?如何实现让我的用户获得与会话ID对应的主体呢?
我有一个简单的Spring应用程序,具有WebSocket功能,到目前为止一切都运行正常。现在我想使用@SendToUser注释从服务器向特定客户端发送消息。但是这会导致错误“忽略消息,没有可用的主体信息”。我理解我在服务器上没有任何登录信息,因此每个用户都是“匿名”的,并且没有主体(暂时不使用Spring Security)。但是每个用户都有一个会话ID。难道不能使用会话ID来区分用户吗?如何实现让我的用户获得与会话ID对应的主体呢?
使用@SendToUser
,并在订阅时在队列前面添加“/user/”(只在订阅方面)。 其余的就像魔法一样运作 :-)
而不是
Java Server: @SendTo("/topic/showResult")
和
JS Client: stompClient.subscribe('/topic/showResult', function(calResult){ ....
用法:
Java 服务器端:@SentToUser("/topic/showResult")
和
JS 客户端:stompClient.subscribe('/user/topic/showResult', function(calResult){ ....
我认为一个解决方案可能是避免使用@SendToUser
,改用原始的SimpMessagingTemplate
并向您控制的目标发送消息以获取开放会话。
例如,假设您有一些与新的WebSocket会话相关的身份标识,您可以订阅具有该标识符的队列:
stomp.subscribe("/queue/chats" + "-" + mycustomidentifier, onmessage);
现在,在Spring WebSocket监听器方面,你可以使用SimpMessagingTemplate
来直接发送你的响应:
@Controller
public class MyController {
@Autowired
private SimpMessagingTemplate simpMessagingTemplate;
@MessageMapping("/chats")
public void handleChat(@Payload ChatMessage message) {
this.simpMessagingTemplate.convertAndSend("/queue/chats-" + "mycustomidentifier", "[" + getTimestamp() + "]:" + message.getMessage());
}
....
在Biju的回答的基础上,利用Stomp生成的会话ID(感谢mariusz2108在类似问题的回答中提供的帮助),以下是我使用Spring的标准示例得出的结果。
SpringFramework客户端:
private SimpMessagingTemplate template;
@Autowired
public GreetingController(SimpMessagingTemplate template) {
this.template = template;
}
@MessageMapping("/hello")
public void greeting(HelloMessage message, @Header("simpSessionId") String sessionId) throws Exception {
template.convertAndSend("/queue/greeting-"+sessionId, new Greeting("Hello, " + message.getName()));
}
JavaScript客户端:
function connect() {
var socket = new SockJS('/gs-guide-websocket');
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
var sessionId = /\/([^\/]+)\/websocket/.exec(socket._transport.url)[1];
console.log("connected, session id: " + sessionId);
stompClient.subscribe('/queue/greeting-'+sessionId, function (greeting) {
showGreeting(JSON.parse(greeting.body).content);
});
});
}
您可以使用Web容器的会话ID(例如JSESSIONID)代替Stomp会话ID,但是现在该Cookie 默认情况下无法从JavaScript访问(对于Tomcat而言),这是一个更困难的问题。
var sessionId = / \ /([^ \ /] +)\ / websocket \ /?$ / .exec(socket._transport.url)[1];
- annih试试这个。它对我有用。
@Autowired
private SimpMessagingTemplate messagingTemplate;
@MessageMapping("/getHello")
public void sendReply( MessageHeaders messageHeaders, @Payload String message, @Header(name = "simpSessionId") String sessionId){
messagingTemplate.convertAndSendToUser(sessionId, "/queue/hello", "Hello "+ message, messageHeaders);
}
这个解决方案对我很有效。
背景:您的应用程序中没有安全性,您想通过会话ID向用户发送消息。换句话说,在我们的情况下,用户ID=会话ID。
private final SimpMessageSendingOperations template;
@MessageMapping("/test")
public void testNotification(@Header("simpSessionId") String sessionId, String name) {
String payload = "Hello, " + name + "!";
template.convertAndSendToUser(sessionId, "/ws/notification/message", payload, createHeaders(sessionId));
}
private MessageHeaders createHeaders(String sessionId) {
SimpMessageHeaderAccessor headerAccessor = SimpMessageHeaderAccessor.create(SimpMessageType.MESSAGE);
headerAccessor.setSessionId(sessionId);
headerAccessor.setLeaveMutable(true);
return headerAccessor.getMessageHeaders();
}
这样,JavaScript 代码片段看起来就像这样:
stompClient.connect(header, function (frame) {
console.log('Connected: ' + frame);
stompClient.subscribe('/user/ws/notification/message', function (greeting) {
console.log(greeting.body);
});
});