經過前一篇博客的講解,咱們大致知道了HTTP協議是什麼,它有什麼組成,以及它的工做原理,那麼在HTTP的不少特色中,有一點叫作,無狀態,就HTTP是一個無狀態的協議,若是須要前面的信息用於處理後邊的請求,那麼在HTTP當中,就須要對前邊的信息進行重發,這一點是很不方便的,那麼爲了解決HTTP在用於須要記錄前邊信息的場景的問題,提出了這麼兩個概念,Session和Cookie。那麼咱們先來了解一下Session是什麼呢?html
Session,顧名思義,中文含義是會話,如同前文所述,它是用於解決一類用來在客戶端與服務器之間保持狀態的解決方案,在java當中討論的Session,一般指的是javax.servlet.http.HttpSession,能夠看出Session它自己是一個對象,那麼在這個對象當中主要包含了如下幾個要素:1.屬性,用於存儲Request當中的各種信息。2.SessionID,用於映射相應Request的標識。也許這麼說,可能有一些不大清晰,那麼咱們仍是老規矩,舉一個栗子來講:java
假設咱們的WebServer是一個商場的儲物處,而每個HTTP Request是一個來商場購物的顧客,那麼顧客須要在商場當中存包,管理員會將顧客的包放到相應的儲物櫃,當中而這個儲物櫃就至關於Session,而且交給顧客相應的號碼牌做爲顧客離開的時候要取包的憑證,而且以後一段時間這個儲物櫃就只交給這個顧客使用了,這個號碼牌就是SessionID。那麼等這個顧客(HTTP Request)下次來的時候,只須要初始相應的號碼牌(SessionID),儲物處(WEB Server)就會將客戶須要用的儲物櫃(Session)交個顧客使用,顧客能夠在儲物櫃裏頭放東西(存入相應的屬性,setAttribute)以及取東西(getAttribute)等,固然,商場的儲物處也能夠將顧客的儲物櫃給取消,而後給其餘客戶使用。當顧客離開商場的時候(這時候顧客變成了HTTP Response),商場的儲物間還會友情的提示儲物櫃的編號告訴顧客(將SessionID放入Response當中),以防顧客下次忘記帶來號碼牌。這樣顧客下次過來的時候,又會帶着相同的號碼牌。mysql
經過這個栗子,咱們能夠很好的理解了Session與HTTP Request和WEB Server之間的關係咯吧?Request和WEB Server就是依靠Session對該次狀態進行記錄,而且下次訪問的時候,就會經過相同的SessionID獲取到上一次的狀態,解決了HTTP的無狀態的問題,那麼咱們在標題當中提到的Cookie又是什麼東西呢?其實,Cookie就是咱們在例子當中提到的 「號碼牌」,這個號碼牌就放在客戶端的(存儲與瀏覽器的)一位顧客不可能一生只去一個商場,那麼這個顧客手上就會有不少 「號碼牌」,當顧客想去其中的某一個商場的時候,就會在本身手裏找一找有沒有那個商場的號碼牌(查找符合做用域的Cookie)而後帶着這個號碼牌去相應的商場進行存包取包等操做。面試
這個例子呢,只是讓咱們對HTTP Request、WEB Server、Cookie、Session、HTTP Response之間的關係作一個大致的瞭解,那麼接下來,咱們開始正經的介紹在HTTP當中的Cookie和Session,以及在面試當中經常遇到過的相關問題。sql
Cookie 機制數據庫
Cookie在瀏覽器的生成,主要是經過拓展HTTP協議來實現的,在第一次訪問WEB Server的時候,WEB Server會在響應的HTTP Response當中的響應報頭添加一行特殊的指示,提示瀏覽器在本地保存相應的cookie(至關於顧客第一次來商場的儲物處存東西,管理員爲顧客分配一個儲物櫃,而後給顧客一個號碼牌,要求顧客要拿着)。而這個Cookie的主要內容主要包括如下幾點:瀏覽器
1.名字:即cookie的名字。tomcat
2.值:在Cookie中存入的值。服務器
3.過時時間:若是不設置過時時間,則表示這個cookie的生命期爲瀏覽器會話期間,只要關閉瀏覽器窗口,cookie就消失了。這種生命期爲瀏覽器會話期的cookie被稱爲會話cookie。會話cookie通常不存儲在硬盤上而是保存在內存裏,固然這種行爲並非規範規定的。若是設置了過時時間,瀏覽器就會把cookie保存到硬盤上,關閉後再次打開瀏覽器,這些cookie仍然有效直到超過設定的過時時間。cookie
4.路徑和域:指定某一個域好比.google.com,也能夠指定一個域下的具體某臺機器好比www.google.com,路徑就是跟在域名後面的URL路徑,好比/或者/foo,路徑與域合在一塊兒就構成了cookie的做用範圍。
這裏提到一點,當設置了過時時間的cookie被存在硬盤以後,能夠在不一樣的瀏覽器進程間共享。對於Mozilla Firefox0.8,全部的進程和標籤頁均可以共享一樣的cookie。
Seesion 機制
session機制是一種服務器端的機制,服務器使用一種相似於散列表的結構(也可能就是使用散列表)來保存信息。當某個客戶端發起HTTP Request,並須要使用一個Session的時候,WEB Server首先會檢查在這個Http Request裏頭有沒有相應的SessionID,若是已包含一個SessionID則說明之前已經爲此客戶端建立過session,服務器就按照session id把這個session檢索出來使用(若是檢索不到,可能會新建一個),若是客戶端的Http Request中不包含session id,則爲此客戶端建立一個session而且生成一個與此session相關聯的session id,session id的值應該是一個既不會重複,又不容易被找到規律以仿造的字符串,這個session id將被在本次響應Http response中返回給客戶端保存。
這裏要格外的提一點,以前的例子當中,一直說SessionID,是用Cookie來進行保存的,這是固然能夠的,cookie的名字都是相似於SEEESIONID,可是當客戶端(瀏覽器)禁用Cookie的話,是否是就意味着這個SessionID無法存儲了呢?固然是不可能的啊。
因爲cookie能夠被人爲的禁止,必須有其餘機制以便在cookie被禁止時仍然可以把session id傳遞迴服務器。常常被使用的一種技術叫作URL重寫,就是把session id直接附加在URL路徑的後面,附加方式也有兩種,一種是做爲URL路徑的附加信息,表現形式爲http://...../xxx;jsessionid=ByOK ... 99zWpBng!-145788764,另外一種是做爲查詢字符串附加在URL後面,表現形式爲http://...../xxx?jsessionid=ByOK ... 99zWpBng!-145788764(這個jsessionid就是用來存儲SessionID的),這兩種方式對於用戶來講是沒有區別的,只是服務器在解析的時候處理的方式不一樣,採用第一種方式也有利於把session id的信息和正常程序參數區分開來。爲了在整個交互過程當中始終保持狀態,就必須在每一個客戶端可能請求的路徑後面都包含這個session id。
瞭解完Session和Cookie機制以後,咱們來看看一些面試當中的乾貨。
Session常見問題
1.Session建立的時間:人們常有一個誤解就是覺得Session是在有客戶端訪問的時候就必定會被建立,然而事實是到某個Server端程序調用了HttpServletRequest.getSession(true)這樣的語句時才被建立,即在打開瀏覽器第一次請求該jsp的時候,服務器會自動爲其建立一個session(JSP沒有顯示關閉Session的時候),在JSP的默認編譯成Servlet時將會自動加上這樣一條語句 HttpSession session = HttpServletRequest.getSession(true);這也是JSP中隱含的 session對象的來歷。若是不須要在JSP當中使用Session的話,須要顯示的聲明關閉Session,<% @page session="false"%>。
注意:訪問*.html的靜態資源由於不會被編譯爲Servlet,也就不涉及session的問題、
2.Session刪除的時間:知足如下三種狀況,則會刪除Session。
1)Session超時:超時指的是連續必定時間服務器沒有收到該Session所對應客戶端的請求,而且這個時間超過了服務器設置的Session超時的最大時間。
2)程序調用HttpSession.invalidate()
3)服務器關閉或服務中止(通常狀況下,session是不作持久化的。)
除了以上狀況,均不會刪除Session,好比關閉瀏覽器,是不會刪除Session的,只會刪除會話Cookie(沒有被存入硬盤的Cookie)
3.session存放在哪裏:存放於服務器的內存當中,也能夠作特殊處理進行持久化,存入數據庫或者硬盤。
4.SessionID的生成和使用:當客戶端第一次請求服務器。且須要應用到Session的時候,服務器會爲客戶端建立一個Session,而且相應的生成一個SessionID用來表示該Session,當瀏覽器下次(session繼續有效時)請求別的資源的時候,瀏覽器會自動地將SessionID放置到請求頭中,服務器接收到請求後就獲得該請求的SessionID,服務器找到該id的Session 返還給請求者(Servlet)使用。一個會話只能有一個Session對象,對Session來講是隻認id不認人。
5.同一客戶端機器屢次請求同一個資源,session是否同樣:對於多標籤的瀏覽器(好比360瀏覽器)來講,在一個瀏覽器窗口中,多個標籤同時訪問一個頁面,session 是一個。對於多個瀏覽器窗口之間,同時或者相隔很短期訪問一個頁面,session是多個的,和瀏覽器的進程有關。
總結一下:Session是一個容器,能夠存放會話過程當中的任何對象,Session由於請求(request對象)而產生,同一個會話中多個request共享了一Session對象,能夠直接從請求中獲取到Session對象,而且其實,session的建立和使用總在服務端,而瀏覽器歷來都沒獲得過session對象。但瀏覽器能夠請求Servlet(jsp也是 Servlet)來獲取session的信息。客戶端瀏覽器真正牢牢拿到的是session ID,而這個對於瀏覽器操做的人來講,是不可見的,而且用戶也無需關心本身處於哪一個會話過程當中。
6.Session共享的方法
1)客戶端Cookie保存:客戶端Cookie保存以cookie加密的方式保存在客戶端.
優勢是減輕服務器端的壓力,每次session信息被寫在客服端。而後經瀏覽器再次提交到服務器。即便兩次請求在集羣中的兩臺服務器上完成,也能夠到達session共享。
2)服務器間Session同步:使用服務器間session同步使用主-從服務器的架構,當用戶在主服務器上登陸後,經過腳本或者守護進程的方式,將session信息傳遞到各個從服務器中,這樣用戶訪問其它的從服務器時,就能夠讀到session信息。 缺點:好比速度慢、不穩定等,另外,若是 session 信息傳遞是主->從單向的,會有一些風險,好比主服務器down了,其它服務器沒法得到 session 信息
3)使用集羣管理Session(如MSM) :使用集羣統一管理Session提供一個集羣保存session共享信息.其餘應用通通把本身的session信息存放到session集羣服務器組。當應用系統須要session信息的時候直接到 session 集羣服務器上讀取。目前大多都是使用 Memcache 來對 Session 進行存儲。目前比較流行的兩種方案:
a) 使用Filter方式:此方式使用過濾器的方式從新對httpRequest 對象進行了包裝,並加入memcached客戶端,此方式的優勢是:使用簡單,把過濾器配置進去便可,另外比較靈活,由於它是在客戶端實現的,配置比較靈活,並且服務器無關,你能夠在任何支持servlet的容器上部署。
b)使用Memcached-Session-Manager,俗稱MSM,是一個用於解決分佈式 tomcat 環境下 session 共享的問題的開源解決方案。它的實現原理爲以tomcat插件的方式部署在服務器,修改了 servlet 容器代碼中的 session 相關代碼,使其鏈接 memcached ,在 memcached 中建立和更新session。
4)把Session持久化到數據庫:將session持久化到數據中這種共享session的方式即將session信息存入數據庫中,其它應用能夠從數據庫中查出session信息。目前採用這種方案時所使用的數據庫通常爲mysql。 利用數據庫共享 session 的方案有必定的實用性,但也有以下缺點:首先 session 的併發讀寫在數據庫中完成,對 mysql 的性能要求比較高;其次,咱們須要額外地實現 session 淘汰(超時)邏輯代碼,即定時從數據庫表中更新和刪除 session 信息,增長了工做量。