【问题标题】:WebSocket Stomp over SockJS - http custom headersWebSocket Stomp over SockJS - http 自定义标头
【发布时间】:2023-11-28 15:16:02
【问题描述】:

我在我的 javascript 客户端中使用 stomp.js 而不是 SockJS。 我正在使用

连接到 websocket
stompClient.connect({}, function (frame) {

stomp over sockJS 连接有 2 个 http 请求:

  1. 请求 /info
  2. http 升级请求

客户端发送所有 cookie。我还想发送自定义标头(例如 XSRF 标头),但没有找到方法。将不胜感激。

【问题讨论】:

  • 看起来无法将自定义 HTTP 标头传递给 WebSocket 握手请求。
  • 有可能,但我不知道如何使用 stomp 客户端。
  • 您的问题解决了吗?我遇到了类似的问题,如果您有解决方案,我想听听您的解决方案。

标签: spring websocket stomp sockjs stompjs


【解决方案1】:

@Rohitdev 所以基本上你不能使用 stompClient 发送任何 HTTP 标头,因为 STOMP 是 websockets 之上的层,只有当 websockets 握手发生时,我们才有可能发送自定义标头。 所以只有 SockJS 可以发送这个 headers,但由于某些原因不要这样做:https://github.com/sockjs/sockjs-client/issues/196

【讨论】:

【解决方案2】:

自定义标题:

stompClient.connect({token: "ABC123"}, function(frame) { ... code ...});

没有自定义标题:

stompClient.connect({}, function(frame) { ... code ...});

在 Javascript 中,您可以使用以下方法提取 STOMP 标头:

  username = frame.headers['user-name'];

在服务器端,如果您使用 Spring Framework,您可以实现一个拦截器来将 HTTP 参数复制到 WebSockets STOMP 标头。

public class HttpSessionHandshakeInterceptor_personalised implements HandshakeInterceptor {

    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response,
            WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {


        // Set ip attribute to WebSocket session
        attributes.put("ip", request.getRemoteAddress());

        // ============================================= CODIGO PERSONAL
        ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
        HttpServletRequest httpServletRequest = servletRequest.getServletRequest();
//        httpServletRequest.getCookies();
//        httpServletRequest.getParameter("inquiryId");
//        httpServletRequest.getRemoteUser();

         String token = httpServletRequest.getParameter("token");


      ...
    }
}

对于没有 STOMP 参数的发送消息:

function sendMessage() {
     var from = document.getElementById('from').value;
     var text = document.getElementById('text').value;
            stompClient.send("/app/chatchannel", {},
               JSON.stringify({'from':from, 'text':text}));
}

在这里您将参数传递到 STOMP 标头中。

function sendMessage() {
     var from = document.getElementById('from').value;
     var text = document.getElementById('text').value;
            stompClient.send("/app/chatchannel", {'token':'AA123'},
               JSON.stringify({'from':from, 'text':text}));
}

【讨论】:

  • 首先它在春季部分不起作用。第二:查看@IRus 答案了解原因
  • 但是我可以用 SockJs 发送参数,我的实现是可行的。
  • 无论我投多少次ServerHttpRequest都看不到标头
  • 我确认,弹簧部分不起作用,没有“token”参数可用
【解决方案3】:

如果您在服务器上使用 Spring boot,请在方法内使用 @Header(name = "token") 注释。

用法-

@Controller
public class SocketController {

    static final String token = "1234";

    @MessageMapping("/send")
    @SendTo("/receive/changes")
    public Object notify(MessageModel message, @Header(name = "token") String header)throws Exception {
        if(!header.equals(token)) {
            // return when headers do not match
            return("Unauthorized");
        }
        // return the model object with associated sent message
        return new MessageModel(message.getMessage());
    } 
}

您应该有一个带有message 变量的MessageModel 类,并且需要getterssetterscontructor

在前端使用 Stomp

用法-

function sendMessage() {
     var text = document.getElementById('text').value;
            stompClient.send("/send/message", {'token':'1234'},
               JSON.stringify({'message':text}));
}

为了增加安全性,您可以在 Spring 中使用 CORS

【讨论】:

    【解决方案4】:

    您必须使用查询作为参数而不是在标题中使用授权。 (?query=token_2222) 例如: var socket = new SockJS('/ws?query=token_2222'); 然后像 Sergio 写的那样在 HandshakeInterceptor 中阅读它

    【讨论】: