一 websocket如何携带参数
相信用过websocket的同学都知道,直接在url后面拼接参数即可。不多做阐述。
var ws = new WebSocket("ws://url?userid=1");
二 websocket如何携带header
最近项目组接到新需求,需要websocket连接时,在header里面传递token,由于token较长,不适合在url中直接拼接。
网上查阅了相关的资料,websocket
没有像http
那样可以只定义请求头的一些参数,只有一个Sec-WebSocket-Protocol
属性用于自定义子协议。
意思就是说可以将token当做一个参数传递给后端,只不过参数的封装形式是以Sec-WebSocket-Protocol为key的一个header属性值。
后台接收到websocket连接后,可以通过下述代码获取到token值。
request.getHeader("Sec-WebSocket-Protocol")
需要注意的是,如果前端通过websocket连接时指定了Sec-WebSocket-Protocol,后端接收到连接后,必须原封不动的将Sec-WebSocket-Protocol头信息返回给前端,否则连接会抛出异常。
--------------------------------------------------------------------------
前端代码格式
var aWebSocket = new WebSocket(url,[protocols]);
url
要连接的URL;WebSocket服务器响应的URL。
protocols 可选
一个协议字符串或者一个包含协议字符串的数组。这些字符串用于指定子协议,这样单个服务器可以实现多个WebSocket子协议(例如,您可能希望一台服务器能够根据指定的协议(protocol)处理不同类型的交互)。如果不指定协议字符串,则假定为空字符串。
--------------------------------------------------------------------------
介绍就到这里,直接上前后端完整代码示例,方便后来者学习。
前端
var webSocket = new WebSocket(url,[token]);
后端
org.springframework.boot
spring-boot-starter-websocket
package com.xx;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.HandshakeInterceptor;
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
import java.util.Objects;
/**
* webSocket握手拦截器
* @since 2022年9月16日16:57:52
*/
@Component
public class PortalHandshakeInterceptor implements HandshakeInterceptor {
private final Logger logger = LoggerFactory.getLogger(PortalHandshakeInterceptor.class);
@Resource
private UserClient userClient;
/**
* 初次握手访问前
* @param request
* @param serverHttpResponse
* @param webSocketHandler
* @param map
* @return
*/
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Map map) {
logger.info("HandshakeInterceptor beforeHandshake start...");
if (request instanceof ServletServerHttpRequest) {
HttpServletRequest req = ((ServletServerHttpRequest) request).getServletRequest();
String authorization = req.getHeader("Sec-WebSocket-Protocol");
logger.info("authorization = {}", authorization);
if (Objects.isNull(userClient)){
userClient = (UserClient) SpringContextUtil.getBean("userClient");
}
TokenVO tokenVO = userClient.checkToken(authorization, authorization);
Long userId = tokenVO.getUserId();
logger.info("userId = {}, tokenVO = {}", userId, tokenVO);
if (Objects.isNull(userId)){
serverHttpResponse.setStatusCode(HttpStatus.FORBIDDEN);
logger.info("【beforeHandshake】 authorization Parse failure. authorization = {}", authorization);
return false;
}
//存入数据,方便在hander中获取,这里只是在方便在webSocket中存储了数据,并不是在正常的httpSession中存储,想要在平时使用的session中获得这里的数据,需要使用session 来存储一下
map.put(MagicCode.WEBSOCKET_USER_ID, userId);
map.put(MagicCode.WEBSOCKET_CREATED, System.currentTimeMillis());
map.put(MagicCode.TOKEN, authorization);
map.put(HttpSessionHandshakeInterceptor.HTTP_SESSION_ID_ATTR_NAME, req.getSession().getId());
logger.info("【beforeHandshake】 WEBSOCKET_INFO_MAP: {}", map);
}
logger.info("HandshakeInterceptor beforeHandshake end...");
return true;
}
/**
* 初次握手访问后,将前端自定义协议头Sec-WebSocket-Protocol原封不动返回回去,否则会报错
* @param request
* @param serverHttpResponse
* @param webSocketHandler
* @param e
*/
@Override
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Exception e) {
logger.info("HandshakeInterceptor afterHandshake start...");
HttpServletRequest httpRequest = ((ServletServerHttpRequest) request).getServletRequest();
HttpServletResponse httpResponse = ((ServletServerHttpResponse) serverHttpResponse).getServletResponse();
if (StringUtils.isNotEmpty(httpRequest.getHeader("Sec-WebSocket-Protocol"))) {
httpResponse.addHeader("Sec-WebSocket-Protocol", httpRequest.getHeader("Sec-WebSocket-Protocol"));
}
logger.info("HandshakeInterceptor afterHandshake end...");
}
}