5.Websocket自定义握手响应(源码分析)

本文详细介绍了如何在WebSocket中自定义握手规则,通过分析@ServerEndpoint注解源码,理解握手过程,并展示了如何在WebsocketEndpointConfig中修改握手规则,存储用户信息如userId、token等,并在事件处理中使用。同时解释了perEndpointConfig和perSessionUserProperties的来源。
摘要由CSDN通过智能技术生成

自定义握手

  在上篇的文章测试中我们使用参数123321作为用户的userId来进行通信;

  实际业务中,一般使用登录用户的userId、userName、token等信息来自定义握手规则,并实现客户端和服务端的点对点信息推送或者广播推送;

@ServerEndpoint注解的源码

  WebSocketServer 中我们应用了@ServerEndpoint注解,来看看源码

package javax.websocket.server;

@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@java.lang.annotation.Target({
   java.lang.annotation.ElementType.TYPE})
public @interface ServerEndpoint {
   
    java.lang.String value();

    java.lang.String[] subprotocols() default {
   };

    java.lang.Class<? extends javax.websocket.Decoder>[] decoders() default {
   };

    java.lang.Class<? extends javax.websocket.Encoder>[] encoders() default {
   };

    java.lang.Class<? extends javax.websocket.server.ServerEndpointConfig.Configurator> configurator() default javax.websocket.server.ServerEndpointConfig.Configurator.class;
}

  首先理解这个类的作用(下图):它可以拦截握手,我们看到最后的一个方法(上面代码),它要求返回一个ServerEndpointConfig.Configurator的子类;
在这里插入图片描述
  我们写一个WebsocketEndpointConfig类去继承它,然后重写它的方法modifyHandshake,这个方法的作用就是修改握手,也就是自定义握手的规则。
在这里插入图片描述

参数:
sec- 握手中涉及的配置对象
request- 开放握手请求。
response- 提议的开放握手响应

  当我们覆盖modifyHandshake方法时可以看到三个参数,我们查看HandshakeRequest的源码:

public interface HandshakeRequest {
   

    static final String SEC_WEBSOCKET_KEY = "Sec-WebSocket-Key";
    static final String SEC_WEBSOCKET_PROTOCOL = "Sec-WebSocket-Protocol";
    static final String SEC_WEBSOCKET_VERSION = "Sec-WebSocket-Version";
    static final String SEC_WEBSOCKET_EXTENSIONS= "Sec-WebSocket-Extensions";

    Map<String,List<String>> getHeaders();

    Principal getUserPrincipal();

    URI getRequestURI();

    boolean isUserInRole(String role);

    /**
     * Get the HTTP Session object associated with this request. Object is used
     * to avoid a direct dependency on the Servlet API.
     * @return The javax.servlet.http.HttpSession object associated with this
     *         request, if any.
     */
    Object getHttpSession();

    Map<String, List<String>> getParameterMap();

    String getQueryString();
}

  源码中的方法里有两个方法是实现握手的关键:

//获取请求中的所有封住的header信息
Map<String,List<String>> getHeaders();
//获取所有请求的参数
Map<String, List<String>> getParameterMap()

  上面我们说了,一般我们使用一般使用登录用户的userId、userName、token等信息来自定义握手规则,而这些信息都可以从这两个方法中获取到;
在这里插入图片描述
  再来看下ServerEndpointConfig,发现这个接口继承了EndpointConfig的接口

public interface ServerEndpointConfig extends EndpointConfig

  好,我们看一下EndpointConfig的源码:

public interface EndpointConfig {
   

    List<Class<? extends Encoder>> getEncoders();

    List<Class<? extends Decoder>> getDecoders();

    Map<String,Object> getUserProperties();
}

  我们发现了这样的一个方法定义:

Map<String,Object> getUserProperties();

  可以看到,它是一个map,从方法名也可以理解到,它是用户的一些属性的存储,那既然它提供了get方法,那么也就意味着我们可以拿到这个map,并且对这里面的值进行操作;

  操作之前的数据结构如下:
在这里插入图片描述
  我们可以看到这个userProperties中在调用的时候存储了websocket的事件属性,现在我们要做的就是将拿到的userId、userName、token等信息存储到userProperties中,在事件的处理方法中使用;

  操作之后的数据结构如下:
在这里插入图片描述
  有个疑问,perEndpointConfig和perSessionUserProperties这两个参数是怎么来的,为什么传入的token会出现在perSessionUserProperties中?

  首先,我们要知道ServerEndpointConfig调用的getUserProperties()是其父类EndpointConfig的方法,EndpointConfig有多个实现类,其中WsPerSessionServerEndpointConfig对其做了解释;
在这里插入图片描述
  WsPerSessionServerEndpointConfig源码:

class WsPerSessionServerEndpointConfig implements ServerEndpointConfig {
   

    private final ServerEndpointConfig perEndpointConfig;
    private final Map<String,Object> perSessionUserProperties =
            new ConcurrentHashMap<>();

    WsPerSessionServerEndpointConfig(ServerEndpointConfig perEndpointConfig) {
   
        this.perEndpointConfig = perEndpointConfig;
        perSessionUserProperties.putAll(perEndpointConfig.getUserProperties());
    }

    @Override
    public List<Class<? extends Encoder>> getEncoders() {
   
        return perEndpointConfig.getEncoders();
    }

    @Override
    public List<Class<? extends Decoder>> getDecoders() {
   
        return perEndpointConfig.getDecoders();
    }

    @Override
    public Map<String,Object> getUserProperties() {
   
        return perSessionUserProperties;
    }

    @Override
    public Class<
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值