Springboot-WebSocket初探-擷取HttpSession問題

來源:互聯網
上載者:User

標籤:情境   stand   影響   ndt   ica   官方   this   syn   author   

換了新工作,第一個任務就是和這個有關,以前沒接觸過,沒辦法,各種度娘、穀哥,大部分都是隻言片語,要麼就是特定的配置環境還不貼配置……,踩坑無數, 遂整理成筆記

WebSocket協議

WebSocket是一種在單個TCP串連上進行全雙工系統通訊的協議。WebSocket通訊協定於2011年被IETF定為標準RFC 6455,並由RFC7936補充規範。WebSocket API也被W3C定為標準。

WebSocket使得用戶端和伺服器之間的資料交換變得更加簡單,允許服務端主動向用戶端推送資料。在WebSocket API中,瀏覽器和伺服器只需要完成一次握手,兩者之間就直接可以建立持久性的串連,並進行雙向資料轉送

STOMP協議

STOMP是面向文本的訊息傳送協議。STOMP用戶端與支援STOMP協議的訊息代理進行通訊。STOMP使用不同的命令,如串連,發送,訂閱,斷開等進行通訊。

具體參考:官方介紹

SockJS

SockJS是一個JavaScript庫,提供跨瀏覽器JavaScript的API,建立了一個低延遲、全雙工系統的瀏覽器和web伺服器之間通訊通道

以上內容出自維基百科和百度百科

環境配置
  1. SpringBoot2.0全家桶
  2. 特別說明一下,現在很多伺服器都支援websocket,我這次寫代碼用的是SpringBoot內建的tomcat
應用情境
  1. 如果只是單純的配置一個建立串連發送訊息,並不難,具體用戶端編寫參考這個 菜鳥教程-websocket
  2. 我需要解決的問題是:當用戶端和伺服器建立串連時,將登入的使用者資訊從httpSession中取出,這個問題的痛點在於,websocket的請求和http請求完全不相關,所以沒有辦法直接擷取HttpSession
實施思路
  1. 伺服器端的編碼實現,具體有兩套方案
    1. 使用繼承的方式,這種方式,我在看Spring官方介紹文檔時貌似也是這種方式實現的
    2. 使用註解的方式:很蛋疼的是我們的項目使用的是這種方式
  2. 具體思路
    1. 雖然websocket的請求和http請求完全不相關,但是如果基於註解的話,EndPoint支援讀取一個配置
    2. 我當時的想法就是在配置中攔截或者擷取HttpSession,事實證明思路是正確的,但是當我按照這個思路去百度Google發現擷取的一律都是null,然後我就崩潰了
具體編碼實現
  1. 只貼核心代碼,完整項目在本文的底部,我放在了github上
  2. 先上核心的伺服器端訊息處理類

    /** * WebSocket主要的訊息類 * @author 侯葉飛 */ //onfigurator = WebsocketConfig.class 該屬性就是我上面提到我們可以自己配置的東西@ServerEndpoint(value = "/api/websocket", configurator = WebsocketConfig.class)@Component@Slf4jpublic class WebSocket {    /*每個瀏覽器串連都會有一個新的會話對象*/    private Session session;    /*用來儲存每個會話的session,靜態不會被執行個體化*/    private static CopyOnWriteArraySet<WebSocket> webSocketSets = new CopyOnWriteArraySet<>();    /**     * 主要用來監聽串連建立,config用來擷取WebsocketConfig中的配置資訊     * @param session     * @param config     */    @OnOpen    public void onOpen(Session session, EndpointConfig config) {        log.info("config:{}", config.getUserProperties().get("name"));        log.info("session:{}", config.getUserProperties().get("sessionid"));        this.session = session;        webSocketSets.add(this);        log.info("【websocket訊息】有新的串連, 總數:{}", webSocketSets.size());    }    @OnClose    public void onClose() {        webSocketSets.remove(this);        log.info("【websocket訊息】串連斷開, 總數:{}", webSocketSets.size());    }    @OnError    public void onError(Throwable e, Session session) {        webSocketSets.remove(this);        log.info("【websocket訊息】串連出錯或未關閉socket:" + e.getMessage());    }    @OnMessage    public void onMessage(String message, Session session) {        for(WebSocket ws:webSocketSets){            ws.session.getAsyncRemote().sendText("廣播:"+message);        }        log.info("【websocket訊息】收到用戶端發來的訊息:{}", message);    }}
  3. 下面代碼就是核心的配置類

    /** * 主要的配置類 *  本類必須要繼承Configurator,因為@ServerEndpoint註解中的config屬性只接收這個類型 * @author 侯葉飛 * */@Configuration@Slf4jpublic class WebsocketConfig extends ServerEndpointConfig.Configurator {    private static final String HttpSession = null;    /* 修改握手,就是在握手協議建立之前修改其中攜帶的內容 */    @Override    public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {        /*如果沒有監聽器,那麼這裡擷取到的HttpSession是null*/        StandardSessionFacade ssf = (StandardSessionFacade) request.getHttpSession();        if (ssf != null) {            HttpSession session = (HttpSession) request.getHttpSession();            sec.getUserProperties().put("sessionid", session);            log.info("擷取到的SessionID:{}",session.getId());        }        sec.getUserProperties().put("name", "小強");        super.modifyHandshake(sec, request, response);    }    @Bean    public ServerEndpointExporter serverEndpointExporter() {        //這個對象說一下,貌似只有伺服器是tomcat的時候才需要配置,具體我沒有研究        return new ServerEndpointExporter();    }}
    1. 僅僅有上面的配置擷取的肯定是null,至於原因,網上說法不一,我也不確定,解決方案如下
    /** * 監聽器類:主要任務是用ServletRequest將我們的HttpSession攜帶過去 * @author 侯葉飛 */@Component //此註解千萬千萬不要忘記,它的主要作用就是將這個監聽器納入到Spring容器中進行管理,相當於註冊監聽吧@Slf4jpublic class RequestListener implements ServletRequestListener {      @Override      public void requestInitialized(ServletRequestEvent sre)  {          //將所有request請求都攜帶上httpSession          HttpSession session = ((HttpServletRequest) sre.getServletRequest()).getSession();          log.info("將所有request請求都攜帶上httpSession {}",session.getId());    }      public RequestListener() {}      @Override      public void requestDestroyed(ServletRequestEvent arg0)  {}  }  
  4. 此外在我Google的過程中有部落格提到需要添加一個WebListener的註解,結果發現基於springboot的話,如果不加也不影響

GitHub項目地址:Demo

以上代碼純屬個人研究,如果有錯誤的地方,各位留言或者發郵件都可以!

Springboot-WebSocket初探-擷取HttpSession問題

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.