网上翻了很多介绍的使用方法都是没有请求头条件下使用的,但是为了安全问题一般都会加上请求头token进行验证,原生websocket是不支持自定义携带请求头的,如果一定要加应该是只能加到Sec-WebSocket-Protocol的位置,如果有更好的方法欢迎指点,
实现代码如下:

前端部分

这一块比较简单,只要在原有的构造方法加上第二个参数,也就是token即可,加上以后在ws请求的请求头’Sec-WebSocket-Protocol‘就会携带着token,后端可以获取并进行相应的解析处理

let socket = new WebSocket('ws://localhost:8080/ws/1', ['验证token']);
  // 连接成功后触发
  socket.onopen = () => {
    console.log('WebSocket 已连接');
    // 向服务端发送消息
    socket.send('Hello Server!');
  };

  // 接收到服务端发送的消息时触发
  socket.onmessage = (event) => {
    console.log(`接收到消息:${event.data}`);
  };

  // 连接关闭时触发
  socket.onclose = (event) => {
    console.log('WebSocket 已关闭', event);
  };

  // 发生错误时触发
  socket.onerror = (error) => {
    console.error('WebSocket 发生错误:', error);
  };

后端部分

添加依赖websocket依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
            <version>${spring-boot.version}</version>
        </dependency>

在使用Spring Boot开发WebSocket应用程序时,需要将WebSocket端点暴露为Spring Bean,以便于Spring容器管理WebSocket端点的生命周期。通常情况下,需要创建一个ServerEndpointExporter实例并将其声明为Spring Bean。

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }

}

WebSocket请求获取请求头Sec-WebSocket-Protocol不为空时,需要返回给前端相同的响应,所以就需要处理:

在 WebSocketConfig 中新增 modifyHandshake方法,用来获取请求头和为返回响应赋值

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.websocket.HandshakeResponse;
import javax.websocket.server.HandshakeRequest;
import javax.websocket.server.ServerEndpointConfig;

@Slf4j
@Component
public class WebsocketConfig  extends ServerEndpointConfig.Configurator{

    /**
     * 重写modifyHandshake方法,获取Sec-WebSocket-Protocol请求头
     * @param sec
     * @param request
     * @param response
     */
    public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
        //当Sec-WebSocket-Protocol请求头不为空时,需要返回给前端相同的响应
        response.getHeaders().put("Sec-WebSocket-Protocol", request.getHeaders().get("Sec-WebSocket-Protocol"));
        super.modifyHandshake(sec, request, response);
    }
}

注意要在**@ServerEndpoint** 注解中加上 configurator = WebSocketConfig.class,也就是将该配置绑定到endpoint上面

import com.alibaba.fastjson.JSON;
import com.wss.gis.view.vo.ServerMessage;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author WuShuaiShuai
 * @since 2023/3/3-16:12
 */
@Slf4j
@Component
@ServerEndpoint(value = "/ws/{param}",configurator = WebsocketConfig.class)
public class CollectEndpoint {
    //用来存储每个连接的客户端chatEndpoint
    private static final ConcurrentHashMap<Long, CollectEndpoint> onLineUsers = new ConcurrentHashMap<>();
    Session session;

    /**
     * 连接建立时调用
     * @param param 用户id
     * @param session 会话
     */
    @OnOpen
    public void onOpen(@PathParam("param")Long param, Session session) {
        this.session = session;
        log.info("{}", onLineUsers.get(param));
        //将当前对象存储到容器中,先查看是否已经链接
        onLineUsers.put(param, this);
        //将当前在线的用户名推送给所用用户端
        log.info("你有新的链接:{}", param);
        onLineUsers.get(param).session.getAsyncRemote().sendText("你好");
    }

    /**
     * 接受客户端的消息时调用
     * @param message 消息
     * @param session 会话
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("收到消息:" + message);
    }

    /**
     * 关闭客户端时调用
     */
    @OnClose
    public void onClose(@PathParam("param")Long param) {
        log.info("关闭链接:{}", param);
        onLineUsers.remove(param);
    }
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("发生错误:{}", error.getMessage());
        error.printStackTrace();
    }

//    public Boolean sendMessage(@NotNull ServerMessage serverMessage, Long toUserId) {
//        log.info("在线人数:{}", onLineUsers.size());
//        CollectEndpoint chatEndpoint = onLineUsers.get(toUserId);
//        boolean flag = false;
//        try {
//            if (chatEndpoint != null) {
//                serverMessage.setFrom(name.toString());
//                serverMessage.setTo(toUserId.toString());
//                chatEndpoint.session.getBasicRemote().sendText(JSON.toJSONString(serverMessage));
//                flag = true;
//            }
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//        return flag;
//    }

}

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐