前幾天在博問中,看到有人提到了有關session的問題,決定自己整理寫一下有關session的原理!說起session,cookie必須是要談的!
目錄
Cookie的介紹(參照計算機網絡)
一、無形之中我們使用的cookie:
使用瀏覽器瀏覽網頁時,當你要登陸時,網頁上有一個記住密碼或自動登陸的選項,當你選擇時,你就使用了Cookie。那么在下次訪問該網站時,你可能就已經自動地登陸了,而不需要從重輸入用戶名和密碼
- 在HTTP響應報文中有一個cookie首部行;
- 在HTTP請求報文中有一個cookie首部行;
- 在用戶端系統中保留有一個cookie文件,由用戶瀏覽器管理;
- 在Web站點有一個后端數據庫;
Cookie的使用
java中的response響應中加入cookie:
Cookie cookie = new Cookie("JSESSIONID", "123456"); cookie.setPath("/test"); response.addCookie(cookie);
java中的request請求中得到cookie:
Cookie[] cookies = request.getCookies();
for (Cookie cookie : cookies) { String cookieName = cookie.getName(); String cookieValue = cookie.getValue(); System.out.println(cookieName + ", " + cookieValue); }
Session的介紹
1、Session的概念
使用Cookie和附加URL參數都可以將上次請求的狀態信息傳遞到下一次請求中,但是如果傳遞的狀態信息較多,將極大降低網絡傳輸效率和增大服務器端程序處理的難度。Session技術是一種會話狀態保存在服務器端的技術,它可以比喻成是醫生發給病人的病歷卡和醫院為每個病人保留的病歷檔案的結合方式。客戶端需要接收、記憶和回送Session的會話標示號,Session可以且通常是借助Cookie來傳遞會話標示號。
2、Session的跟蹤會話機制
Servlet API規范中定義了一個HttpSession接口,HttpSession接口定義了各種管理和操作會話狀態的方法。HttpSession對象是保持會話狀態信息的存儲結構,一個客戶端在WEB服務器端對應一個各自的HttpSession對象。Web服務器並不會在客戶端開始訪問它時就創建HttpSession對象,只有客戶端訪問某個能與客戶端開啟會話的Servlet程序是,Web應用程序才會創建一個與該客戶端對應的HttpSession對象。Web 服務器為HttpSession對象分配一個獨一無二的會話標示號,然后在響應消息中將這個會話標示號傳遞給客戶端。客戶端需要記住會話標示 號,並在后續的每次訪問請求中都把這個會話標示號傳送給Web服務器,Web服務器程序依據回傳的會話標示號就知道這次請求的客戶端發出的,從而選擇與之 對應的HttpSession對象。
3、Session的跟蹤機制
Web 應用程序創建與某個客戶端對應的HttpSession對象后,只要沒有超出一個限定的空閑時段,HttpSession對象就駐留在Web 服務器內存之中,該客戶端此后訪問任意的servlet程序時,它們都使用與客戶端對應的那個已存在的Httpsession對象。HttpSession 接口中專門定義了一個SetAttribute方法將對象存儲到HttpSession對象中,還定義了一個 getAttribute方法來檢索存儲在Httpsession對象中的對象,存儲進Httpsession對象中的對象可以被屬於同一個會話的各個請 求的處理程序共享。Session是實現網上商城的購物車的最佳方案,存儲在某個客戶Session中的一個集合對象就可充當給客戶的一個購物車。
4、Session的超時管理
Web服務器無法判斷當前的客戶端瀏覽器是否還會繼續訪問,也無法檢測客戶端瀏覽器是否關閉,所以,即使客戶已經離開或關閉了瀏覽器,Web服務器還要保留與之對應的Httpsession對象。隨着時間的推移而不斷增加新的訪問客戶端,Web服務器內存中將會因此積累起大量的不斷不在使用的Httpsession對象,並將最終導致服務器內存耗盡。Web服務器采用“超時限制”的辦法來判斷客戶端是否還在繼續訪問,如果某個客戶端在一定的時間之內沒有發出后續請求,Web服務器則認為客戶端已經停止了活動,結束與該客戶端的會話並將與之對應的Httpsession對象變成垃圾。如果客戶端瀏覽器超時后再發出訪問請求,Web服務器則認為這是一個新的會話開始,將為之創新的HttpSession對象和分配新的會話標示號。
session的使用
session中存儲數據:
String username = request.getParameter("username");
HttpSession session = request.getSession(); System.out.println(session.getId()); session.setAttribute("username", username);
session中得到數據:
HttpSession httpSession = request.getSession();
String username = (String)httpSession.getAttribute("username");
session的原理
我們創建一個項目來分析session的原理:
一、創建一個主頁index.jsp:
<form action="ContractListServlet" method="get"> username: <input type="text" name="username"/><br> <input type="submit" value="submit"> </form>
清除瀏覽器所有cookie,訪問url:http://localhost:8080/SessionTest/
詳細的請求頭部:
GET /SessionTest/ HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
詳細的響應頭部:
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=5973D26B6164CDDAFF190965C0B4677C; Path=/SessionTest/; HttpOnly
Content-Type: text/html;charset=ISO-8859-1
Content-Length: 418
Date: Tue, 15 Mar 2016 10:25:12 GMT
保存在瀏覽器的cookie:
說明:
- 當我們清除cookie,向tomcat服務器發送請求時,瀏覽器首先會檢查是否存在cookie文件(因為我們已經清除了cookie,所以找不到cookie)。第一次訪問,沒有cookie,直接發送請求。
- tomcat服務器發現請求中沒有cookie頭部,於是為用戶創建一個sessionid,用作標識這個用戶的會話,並且在返回給用戶的響應中增加了cookie的頭部信息,該cookie的path為該項目的上下文/SessionTest。
- 瀏覽器接收響應,檢查響應,發現cookie的頭部,把cookie保存起來
- 當cookie還存在時,(也就是人們常說的再次請求)瀏覽器檢查自身保存的cookie,如果host與path都符合。那么在請求的頭部增加該符合的cookie信息
- tomcat服務器接收到該cookie,得到cookie中的JSESSIONID的值與先前保存的sessionid做比較,如果一致,則服務器視為是同一個會話
二、創建ContractListServlet,以響應index.jsp的提交
String username = request.getParameter("username");
HttpSession session = request.getSession(); System.out.println(session.getId()); session.setAttribute("username", username); Cookie cookie = new Cookie("JSESSIONID", "123456"); cookie.setPath("/test"); response.addCookie(cookie); request.getRequestDispatcher("/list.jsp").forward(request, response);
填寫內容linux,點擊提交:url為http://localhost:8080/SessionTest/ContractListServlet?username=linux
詳細的請求頭部:
GET /SessionTest/ContractListServlet?username=linux HTTP/1.1 Host: localhost:8080 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Referer: http://localhost:8080/SessionTest/ Cookie: JSESSIONID=5973D26B6164CDDAFF190965C0B4677C Connection: keep-alive
詳細的響應頭部:
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=123456; Path=/test
Content-Type: text/html;charset=ISO-8859-1
Content-Length: 331
Date: Tue, 15 Mar 2016 10:29:25 GMT
保存的cookie:現在有兩個了
三、 只要我們訪問的url是這樣的形式http://localhost:8080/cookiePath/xxx/xx,瀏覽器都會攜帶cookie信息去發送請求的:
- localhost是服務器的地 址,
- 8080是服務器的端口,
- cookiePath是cookie的path(圖片見上),
由於上述我們已經有了兩個cookie,它們的path分別為, /test和/SessionTest,於是測試訪問url:http://localhost:8080/test/jjii
雖然報錯404,但是cookie信息仍舊在請求當中:
GET /test/jjii HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Cookie: JSESSIONID=123456
Connection: keep-alive
關閉瀏覽器,cookie被自動清除,所以用戶再次的請求,瀏覽器沒有找到cookie,會像上述第一次訪問一樣,請求中沒有cookie的頭部。
四、 我們改動ContractListServlet的代碼,在response中另外再增加兩個cookie2:以下是加了之后的代碼
Cookie cookie = new Cookie("JSESSIONID", "123456");
cookie.setPath("/test");
Cookie cookie3 = new Cookie("JSESSIONID", "123456");
cookie3.setPath("/SessionTest/");
Cookie cookie2 = new Cookie("df", "456789");
cookie2.setPath("/");
response.addCookie(cookie);
response.addCookie(cookie2);
response.addCookie(cookie3);
再次訪問到從頭開始訪問到url:http://localhost:8080/SessionTest/ContractDetailServlet
詳細的請求頭部:
GET /SessionTest/ContractListServlet?username=linux HTTP/1.1 Host: localhost:8080 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Referer: http://localhost:8080/SessionTest/ Cookie: JSESSIONID=3EF72ED7EC55DA676714F773E9110DB9 Connection: keep-alive
詳細的響應頭部:
HTTP/1.1 200 OK Server: Apache-Coyote/1.1 Set-Cookie: JSESSIONID=123456; Path=/test df=456789; Path=/ JSESSIONID=123456; Path=/SessionTest/ Content-Type: text/html;charset=ISO-8859-1 Content-Length: 321 Date: Tue, 15 Mar 2016 12:04:00 GMT
瀏覽器中的cookie有三條:
- name: JSESSIONID, content: 123456, path: /test
- name: df, content: 456789, path: /
- name: JSESSIONID, content: 123456, path: /SessionTest/
結果分析:
- 首先瀏覽器請求時,會攜帶cookie頭部的:JSESSIONID=5DA63C198B1BBF3930A3CE7EC8613207
- 然后在返回的時候,在響應頭部加了三個cookie信息,由於cookie3的名字與路徑都與tomcat服務器默認返回的cookie一致,所以導致了該cookie被代碼中的cookie3覆蓋
五、接着上面的程序,我們添加list.jsp到ContractDetailServlet的請求:http://localhost:8080/SessionTest/ContractDetailServlet
詳細的頭部請求:
GET /SessionTest/ContractDetailServlet HTTP/1.1 Host: localhost:8080 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Referer: http://localhost:8080/SessionTest/ContractListServlet?username=linux Cookie: JSESSIONID=123456; df=456789 Connection: keep-alive
詳細的頭部響應:
HTTP/1.1 200 OK Server: Apache-Coyote/1.1 Set-Cookie: JSESSIONID=D0ECF2D2EF3946CBBB34BC7E4A426D94; Path=/SessionTest/; HttpOnly Content-Length: 0 Date: Tue, 15 Mar 2016 12:06:19 GMT
瀏覽器中的cookie有三條:
- name: JSESSIONID, content: 123456, path: /test
- name: df, content: 456789, path: /
- name: JSESSIONID, content: D0ECF2D2EF3946CBBB34BC7E4A426D94, path: /SessionTest/
結果分析:
- 首先瀏覽器找到匹配/SessionTest的cookie,找到了cookie2(path /)與cokie3(path /SessionTest/ ),在請求中加入這兩個cookie
- tomcat服務器接收到請求,發現cookie的sessionid與自身保存的不一致,於是為用戶創建了一個sessionid,並把cookie加入到返回的頭部
- 瀏覽器接收到響應的報文,把cookie保存起來,tomcat服務器發送的cookie覆蓋了瀏覽器原來的cookie3
以上是我個人對了session的理解,不正確的地方,還望大家斧正!