乾貨,一文帶你超詳細瞭解Session的原理及應用

session 簡介

session 是我們 jsp 九大隱含對象的一個對象。

session 稱作域對象,他的作用是保存一些信息,而 session 這個域對象是一次會話期間使用同一個對象。所以這個對象可以用來保存共享數據。

  • 使用 Cookie 有一個非常大的侷限,就是如果 Cookie 很多,則無形的增加了客戶端與服務端的數據傳輸量。而且由於瀏覽器對 Cookie 數量的限制,註定我們不能再 Cookie 中保存過多的信息,於是 Session 出現。
  • Session 的作用就是在服務器端保存一些用戶的數據,然後傳遞給用戶一個名字為JSESSIONID 的 Cookie,這個 JESSIONID 對應這個服務器中的一個 Session 對象,通過它就可以獲取到保存用戶信息的 Session。

session 是基於 cookie 的。

在用戶第一次使用 session 的時候(訪問 jsp 頁面會獲取 session,所以一般訪問 index.jsp 就算是第一次使用 session 了),服務器會為用戶創建一個 session 域對象。使用jsessionid 和這個對象關聯,這個對象在整個用戶會話期間使用。響應體增加 set-cookie:jsessionid=xxx 的項。用戶下次以後的請求都會攜帶 jsessionid 這個參數,我們使用request.getSession()的時候,就會使用 jsessionid 取出 session 對象。

session 原理圖:

乾貨,一文帶你超詳細瞭解Session的原理及應用


回到頂部

HttpSession 的生命週期

什麼時候創建 HttpSession 對象

①. 對於 JSP: 是否瀏覽器訪問服務端的任何一個 JSP, 服務器都會立即創建一個 HttpSession 對象呢?

不一定。

  • 若當前的 JSP 是客戶端訪問的當前 WEB 應用的第一個資源,且 JSP 的 page 指定的 session 屬性值為 false,則服務器就不會為 JSP 創建一個 HttpSession 對象;
  • 若當前 JSP 不是客戶端訪問的當前 WEB 應用的第一個資源,且其他頁面已經創建一個 HttpSession 對象,則服務器也不會為當前 JSP 頁面創建一個 HttpSession 對象,而會把和當前會話關聯的那個 HttpSession 對象返回給當前的 JSP 頁面.

②. 對於 Serlvet: 若 Serlvet 是客戶端訪問的第一個 WEB 應用的資源,則只有調用了 request.getSession() 或 request.getSession(true) 才會創建 HttpSession 對象

page 指令的 session=“false“ 表示什麼意思?

當前 JSP 頁面禁用 session 隱含變量!但可以使用其他的顯式的 HttpSession 對象

在 Serlvet 中如何獲取 HttpSession 對象?

request.getSession(boolean create): 

create 為 false, 若沒有和當前 JSP 頁面關聯的 HttpSession 對象, 則返回 null; 若有, 則返回 true

create 為 true, 一定返回一個 HttpSession 對象. 若沒有和當前 JSP 頁面關聯的 HttpSession 對象, 則服務器創建一個新的HttpSession 對象返回, 若有, 直接返回關聯的.

request.getSession(): 等同於 request.getSession(true)

什麼時候銷燬 HttpSession 對象

①. 直接調用 HttpSession 的 invalidate() 方法: 該方法使 HttpSession 失效

②. 服務器卸載了當前 WEB 應用.

③. 超出 HttpSession 的過期時間.

④. 並不是關閉了瀏覽器就銷燬了 HttpSession.

回到頂部

session 使用

獲取 session 對象

HttpSession session = request.getSession();

session 是我們的四大域對象之一。用來保存數據。常用的方法

session.setAttribute("user", new Object()); session.getAttribute("user");
session.setMaxInactiveInterval(60*60*24);//秒為單位
session.invalidate();//使 session 不可用

Session 時 效

①、基本原則

Session 對象在服務器端不能長期保存,它是有時間限制的,超過一定時間沒有被訪問過的 Session 對象就應該釋放掉,以節約內存。所以 Session 的有效時間並不是從創建對象開始計時,到指定時間後釋放——而是從最後一次被訪問開始計時,統計其“空閒” 的時間。

②、默認設置

在全局 web.xml 中能夠找到如下配置:

<session-config>
<session-timeout>30/<session-timeout>
/<session-config>

③、手工設置

session.setMaxInactiveInterval(int seconds) 
session.getMaxInactiveInterval()

④、強制失效

session.invalidate()

⑤、可以使 Session 對象釋放的情況

Session 對象空閒時間達到了目標設置的最大值,自動釋放

Session 對象被強制失效

Web 應用卸載服務器進程停止

URL 重寫

在整個會話控制技術體系中,保持 JSESSIONID 的值主要通過 Cookie 實現。但 Cookie 在瀏覽器端可能會被禁用,所以我們還需要一些備用的技術手段,例如:URL 重寫。

1)URL 重寫其實就是將 JSESSIONID 的值以固定格式附著在 URL 地址後面,以實現保持

JSESSIONID,進而保持會話狀態。這個固定格式是:URL;jsessionid=xxxxxxxxx

例如:

targetServlet;jsessionid=F9C893D3E77E3E8329FF6BD9B7A09957

2) 實 現 方 式 :

response.encodeURL(String)
response.encodeRedirectURL(String)

例如:

//1.獲取Session對象
HttpSession session = request.getSession();
//2.創建目標URL地址字符串

String url = "targetServlet";
//3.在目標URL地址字符串後面附加JSESSIONID的值
url = response.encodeURL(url);
//4.重定向到目標資源
response.sendRedirect(url);

Session 的活化和鈍化

Session 機制很好的解決了 Cookie 的不足,但是當訪問應用的用戶很多時,服務器上就會創建非常多的 Session 對象,如果不對這些 Session 對象進行處理,那麼在 Session 失效之前,這些 Session 一直都會在服務器的內存中存在。那麼就,就出現了 Session 活化和鈍化的機制。

1)Session 鈍化:

Session 在一段時間內沒有被使用時,會將當前存在的 Session 對象序列化到磁盤上,而不 再 佔 用 內 存 空 間 。

2)Session 活化:

Session 被鈍化後,服務器再次調用 Session 對象時,將 Session 對象由磁盤中加載到內存中使用。

如果希望 Session 域中的對象也能夠隨 Session 鈍化過程一起序列化到磁盤上,則對象的實現類也必須實現 java.io.Serializable 接口。不僅如此,如果對象中還包含其他對象的引用,則被關聯的對象也必須支持序列化,否則會拋出異常:java.io.NotSerializableException

回到頂部

表單重複提交問題

什麼是表單重複提交?

同一個表單中的數據內容多次提交到服務器。 危害:

服務器重複處理信息,負擔加重。

如果是保存數據可能導致保存多份相同數據。

推薦博客

程序員寫代碼之外,如何再賺一份工資?

幾種重複提交

1)提交完表單後,直接刷新頁面,會再次提交。

- 根本原因:Servlet 處理完請求以後,直接轉發到目標頁面。

- 這樣整一個業務,只發送了一次請求,那麼當你在瀏覽器中點擊刷新按鈕或者狂按 f5,會一直都會刷新之前的請求

解決方案:使用重定向跳轉到目標頁面

2)提交表單後,由於網速差等原因,服務器還未返回結果,連續點擊提交按鈕,會重 復提交。

- 根本原因:按鈕可以多次點擊

- 解決方案:通過 js,使得按鈕只能提交一次。

$(“#form1”).submit(function(){
$(“#sub_btn”).prop(“disabled”,true);
})

3)表單提交後,點擊瀏覽器回退按鈕,不刷新頁面,點擊提交按鈕再次提交表單

- 根本原因:服務器並不能識別請求是否重複。

- 解決方案:使用 token 機制。

1、頁面生成時,產生一個唯一的 token 值。將此值放入 session

2、表單提交時,帶上這個 token 值。

3、服務端驗證 token 值存在,則提交表單,然後移除此值。驗證 token 不存在,說明是之前驗證過一次被移除了,所以是重複請求。不予處理

原理:

乾貨,一文帶你超詳細瞭解Session的原理及應用

代碼:

jsp 頁面

  String token = System.currentTimeMillis() + ""; 
  request.getSession().setAttribute(token, "");
%>

  

測試表單重複提交


  
  


Servlet

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
String token = request.getParameter("token");
Object attribute = session.getAttribute(token);
response.setContentType("text/html;charset=UTF-8");
if(attribute!=null){
session.removeAttribute(token);
response.getWriter().write("請求成功!");
}else{
response.getWriter().write("請不要重複請求!");
}
}

其實防止重複提交的核心就是讓服務器有一個字段能來識別此次請求是否已經執行。 這個字段需要頁面傳遞過來,因為只要回退回去的頁面,字段都是一致的。不會變化, 通過這個特性我們想到了 token 機制來防止重複提交

歡迎工作一到五年的Java工程師朋友們加入Java程序員開發: 721575865

群內提供免費的Java架構學習資料(裡面有高可用、高併發、高性能及分佈式、Jvm性能調優、Spring源碼,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構資料)合理利用自己每一分每一秒的時間來學習提升自己,不要再用"沒有時間“來掩飾自己思想上的懶惰!趁年輕,使勁拼,給未來的自己一個交代!


分享到:


相關文章: