我有个项目,希望在 REST 接口使用 SessionID 作为 Token,这样能简化和用熟悉的方式处理会话数据,在 URL 附加 ;jsessionid= 太丑,传递 Cookie 的话 APP 开发又嫌麻烦,就想通过普通的 GET/POST 参数或自定义 HTTP BODY 来传递 SessionID。
现在的 Servlet 都不再支持通过 ID 获取 Session,搜到的一些方案,比如用监听器来记录 Session,但我不喜欢这种方式,1是我觉得冗余,2是不想自己存储更不想放在内存里;SessionManager 的话就是自定存储了,目前 tomcat,jetty 等的 session 已经满足我的需求了,没必要找这个麻烦。
我查了下 Tomcat 的源码找到了他的 Request 里有 setRequestedSessionId 的方法,只要在 getSession 之前调用就行,但这不是 ServletRequest 接口里的方法,我的项目不一定运行在 Tomcat 里。
来问问有什么简单的方式解决这个问题没?
天蓬老师2017-04-17 17:59:18
搞定了,我查了Tomcat,Jetty 各自的Request (HttpServletRequest 的實作),都透過一個setRequestedSessionId(String) 來設定會話id,如是我用反射的方式來取得和呼叫此方法,在getSession 之前設定sessionId,經過在Jetty 上實驗有效,再去試試Tomcat。這兩種容器是我常用的,遇到其他容器再看了。
程式碼簡簡單單:
try {
request.getClass ()
.getMethod("setRequestedSessionId", String.class)
.invoke (request , id);
} catch ( NoSuchMethodException ex) {
// Log
} catch (IllegalAccessException |
IllegalArgumentException |
InvocationTargetException ex) {
// Log
}
呵呵!
需要注意,必須在目前請求首次呼叫 getSession 之前執行才行,尤其註意上層是否有 Filter 中使用到 Session
2016/05/21 更新實驗結果
以上方法 SessionID 是可以換掉的,但是卻取不出來 Session,因取時還會對 Session 進行驗證,追蹤 Jetty 的源碼發現,設定 Session 物件是在初始化 Request 的時候,如下圖:
此時還沒進行到 Servlet 和 Filter,無從下手,因此看來重設沒那麼簡單。
以上只對 Jetty 做了實測,結果失敗。 Tomcat 沒實驗,看原始碼有 changeSessionId(String) 方法,看邏輯應該是可以的。
2016/05/21 再次更新結果
經過不斷的折騰,用以下程式碼重設 sessionId 成功:
try {
Object obj;
obj = req.getClass ()
.getMethod("getSessionManager")
.invoke (req);
obj = obj.getClass ()
.getMethod("getHttpSession" , String.class)
.invoke (obj, sid);
req.getClass ()
.getMethod("setSession", HttpSession.class)
.invoke (req, (HttpSession) obj);
} catch ( NoSuchMethodException ex ) {
// Log
} catch (IllegalAccessException |
IllegalArgumentException |
InvocationTargetException ex ) {
// Log
}
在此之後執行的程式什麼也不用變,可正常使用 request.getSession() 來讀寫 Session, 此方法針對 Jetty 寫的.
2015/05/22 Tomcat 實測更新
吃完早餐無聊,追蹤了下Tomcat 的程式碼,使用Tomcat 7,8 兩個版本,發現其交給用戶Servlet 的Request 物件是一個叫RequestFacade 的代理類,此類僅對HttpServletRequest 介面的方法做了實現,隱藏了他的Request 對象,因此無法呼叫到org.apache.catalina.connector.Request 的setRequestedSessionId 等方法。
看來也只能針對 Jetty 實現此 Hack 了。
結果雖然不太樂觀,且沒準 Jetty 在之後的版本裡也會隱藏那些方法,不過這個實驗過程又對這兩種應用容器有了更進一步的了解。 Cookie 也好,URL Path Parameter 也好,GET/POST 參數也好,只是在請求資料的不同位置攜帶 Session Token 而已,在客戶端對連接做個簡單封裝也許更方便.