WebSocket獲取httpSession空指針異常的解決辦法


小坑:使用requestListner解決不了這個問題!

如何獲取HttpSession

在使用webSocket實現p2p或者一對多聊天功能的時候我們經常會有這樣的需求:webSocket服務端需要獲取到用戶使用數據庫的用戶信息登錄后的HttpSession獲取個人資料信息。
於是,你會使用這樣的代碼:

package com.xinyulee.ws; import javax.servlet.http.HttpSession; import javax.websocket.HandshakeResponse; import javax.websocket.server.HandshakeRequest; import javax.websocket.server.ServerEndpointConfig; import javax.websocket.server.ServerEndpointConfig.Configurator; /** * Created by zipple on 2017/11/14. * 協助server獲取http session */ public class HttpSessionWSHelper extends Configurator { @Override public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) { System.out.println("調用modifyHandshake方法..."); HttpSession session = (HttpSession) request.getHttpSession();//session有可能為空 if (session!=null){ System.out.println("獲取到session id:"+session.getId()); sec.getUserProperties().put(HttpSession.class.getName(),session); }else{ System.out.println("modifyHandshake 獲取到null session"); } } } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

然后在服務端這樣配置:

@ServerEndpoint(value ="/chatRoom/{username}",configurator=HttpSessionWSHelper.class,encoders = {ServerEncoder.class}) //encoders = {ServerEncoder.class}用於指定sendObject()方法調用的解析器 
  • 1
  • 2
  • 3

RequestListner解決不了這個問題的原因

在使用上述方法配置完成以后我滿懷信心的進行測試,但是意外的發現了Tomcat Localhost Log下報了null pointer exception。
經過調試,發現了modifyHandshake方法並不能獲取到HttpSession,在上述HttpSessionWSHelper 類代碼中可以看到我對它進行了判空處理。但是這樣並不能起到什么實際上的作用。我們需要弄明白為什么HandshakeRequest 獲取不到HttpSession。
一開始,我試着去百度了一下,發現有這樣的代碼:

package com.xinyulee.listener; import com.xinyulee.util.Log; import javax.servlet.ServletRequestEvent; import javax.servlet.ServletRequestListener; import javax.servlet.annotation.WebListener; import javax.servlet.http.HttpServletRequest; /** * Created by zipple on 2017/11/14. */ @WebListener public class RequestListener implements ServletRequestListener { public void requestInitialized(ServletRequestEvent sre) { //將所有request請求都攜帶上httpSession----這樣會創建新的session!導致重新創建了會話 Log.info("request--:"+sre.getServletRequest().getLocalAddr()); ((HttpServletRequest) sre.getServletRequest()).getSession(); } public RequestListener() { // TODO Auto-generated constructor stub } public void requestDestroyed(ServletRequestEvent arg0) { // TODO Auto-generated method stub } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

網上解釋說,是因為進行ws連接的時候並沒有HttpSession處於激活狀態,於是便不能獲取到HttpSession。他們給出的解決辦法是對每一個request請求調用sre.getServletRequest()).getSession()方法。
這樣的確可以解決空指針異常的問題,但是新問題又出現了。
在沒有HttpSession激活狀態的時候,使用getSession()方法會新建一個HttpSession,也就是說實際上這個監聽器是在沒有激活HttpSession的情況下不斷新建會話。
這樣已經完全偏離了我們程序的需求:獲取同時在線的HttpSession中保存的個人信息。
那么怎么辦呢?
事實上,這個空指針異常的根源並不是出在我們后端代碼上。

localhost和127.0.0.1其實並不是同一個連接

在前端連接WebSocket的時候,我的代碼是這樣的:

   loadWS("ws://127.0.0.1/chatRoom/null");
  • 1

然而瀏覽器地址欄是這樣的:

    http://localhost:8080/
  • 1

網上解釋說如果不使用同一個host,則會創建不同的連接請求。具體細節有興趣的朋友可以去了解一下。
於是我們可以這樣拼接一下:

    var host = window.location.host; var url = "ws://"+host+"/chatRoom/null";
  • 1
  • 2

這樣便可以正常建立ws請求,並且能夠使用自定義的HttpSessionWSHelper 類獲取到HttpSession了


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM