在Web發展史中,咱們知道瀏覽器與服務器間採用的是http協議,而這種協議是無狀態的,因此這就致使了服務器沒法知道是誰在瀏覽網頁,但很明顯,一些網頁須要知道用戶的狀態,例如登錄,購物車等。java
因此爲了解決這一問題,前後出現了四種技術,分別是隱藏表單域,URL重寫,cookie,session。而用的最多也是比較重要的就是cookie和session了。apache
首先來了解cookie瀏覽器
cookie是瀏覽器保存在用戶電腦上的一小段文本,通俗的來說就是當一個用戶經過http訪問到服務器時,服務器會將一些Key/Value鍵值對返回給客戶端瀏覽器,並給這些數據加上一些限制條件,在條件符合時這個用戶下次訪問這個服務器時,數據經過請求頭又被完整地給帶回服務器,服務器根據這些信息來判斷不一樣的用戶。bash
也就是說,cookie是服務器傳給客戶端並保存在客戶端的一段信息,這個Cookie是有大小,數量限制的!!服務器
當前Cookie有兩個版本,分別對應兩種設置響應頭:「Set-Cookie」和「Set-Cookie2」。在Servlet中並不支持Set-Cookie2,因此咱們來看看Set-Cookie的屬性項:cookie
屬性項 | 屬性項介紹 |
NAME=VALUE | 鍵值對,能夠設置保存的Key/Value,這裏NAME不能和其餘屬性項名字同樣 |
Expires | 過時時間,在這個時間點後Cookie失效 |
Domain | 生成Cookie域名 |
Path | 該Cookie是在當前那個路徑下生成的 |
Secure | 加密設置,設置他以後,只會在SSH鏈接時纔會回傳該Cookie |
如今,咱們假設這裏有兩個域名:session
域名A:a.b.f.com.cn
域名B:c.d.f.com.cndom
顯然,域名A和域名B都是f.com.cn的子域名加密
綜上所述,咱們知道了domain的用處,聰明的小夥伴已經發現了,單點登錄就是用這個原理實現的。spa
Web服務器經過發送一個稱爲Set-Cookie的http消息來建立一個Cookie:
Set-Cookie: value[; expires=date][; domain=domain][; path=path][; secure]
這裏咱們思考一個問題,當咱們在服務器建立多個Cookie時,這些Cookie最終是在一個Header項中仍是以獨立的Header存在的呢?
int size = headers.size();
for(int i = 0;i < size;i++){
outputBuffer.sendHeader(headers.getName(i),headers.getValue(i));
}
複製代碼
++ 接着,在客戶端進行保存,如何保存呢?這裏又要對Cookie進行進一步的瞭解。 ++
所謂會話級別Cookie,就是在瀏覽器關閉以後Cookie就會失效。
保存在硬盤的Cookie,只要設置了過時時間就是硬盤級別Cookie。
好的,如今cookie保存在了客戶端,當咱們去請求一個URL時,瀏覽器會根據這個URL路徑將符合條件的Cookie放在請求頭中傳給服務器。
各位客官看到這裏實屬不易,😀,但咱們仍是要想一想,Cookie是有大小限制和數量限制的,而且愈來愈多的Cookie表明客戶端和服務器的傳輸量增長,可不能夠每次傳的時候不傳全部cookie值,而只傳一個惟一ID,經過這個ID直接在服務器查找用戶信息呢?答案是有的,這就是咱們的session。
Session是基於Cookie來工做的,同一個客戶端每次訪問服務器時,只要當瀏覽器在第一次訪問服務器時,服務器設置一個id並保存一些信息(例如登錄就保存用戶信息,視具體狀況),並把這個id經過Cookie存到客戶端,客戶端每次和服務器交互時只傳這個id,就能夠實現維持瀏覽器和服務器的狀態,而這個ID一般是NAME爲JSESSIONID的一個Cookie。
當瀏覽器不支持Cookie功能時,瀏覽器會將用戶的SessionCookieName(默認爲JSESSIONID)重寫到用戶請求的URL參數中。格式:/path/Servlet;name=value;name2=value2?Name3=value3
會根據javax.servlet.request.ssl_session屬性值設置SessionID。
注:若是客戶端支持Cookie,又經過URL重寫,Tomcat仍然會解析Cookie中的SessionID並覆蓋URL中的SessionID
咱們先看session工做的時序圖
當客戶端訪問到服務器,服務器會爲這個客戶端經過request.getSession()方法建立一個Session,若是當前SessionID尚未對應的HttpSession對象,就建立一個新的,並添加到org.apache.catalina.Manager的sessions容器中保存,這就作到了對狀態的保持。固然,這個SessionID是惟一的
由圖可知,session對象已經保存在了Manager類中,StandardManager做爲實現類,經過requestedSessionId從StandardManager的sessions集合中取出StandardSession對象。
當Servlet容器關閉:
StandardManager將持久化沒過時的StandardSession對象(必須調用Servlet容器中的stop和start命令,不能直接kill)
當Servlet容器重啓時:
StandardManager初始化會重讀這個文件,解析出全部session對象。
這裏有一個誤區,也是我以前的錯誤理解,就是我將session的生命週期理解成一次會話,瀏覽器打開就建立,瀏覽器關閉就銷燬,這樣理解是錯的!!
session的聲明週期是從建立到超時過時
也就是說,當session建立後,瀏覽器關閉,會話級別的Cookie被銷燬,若是沒有超過設定時間,該SessionID對應的session是沒有被銷燬的,
檢查每一個Session是否失效是在Tomcat的一個後臺線程完成的(backgroundProcess()方法中);除了後臺進程檢驗session是否失效外,調用request.getSession()也會檢查該session是否過時,固然,調用這種方法若是過時的話又會從新建立一個新的session。
Session將信息保存到服務器,Cookie將信息保存在客戶端
當瀏覽器第一次訪問服務器時,服務器建立Session並將SessionID經過Cookie帶給瀏覽器保存在客戶端,同時服務器根據業務邏輯保存相應的客戶端信息保存在session中;客戶端再訪問時上傳Cookie,服務器獲得Cookie後獲取裏面的SessionID,來維持狀態。
參考:alibaba叢書《深刻分析Java Web》