Java中Cookie和Session的那些事兒
Cookie和Session都是為了保持用戶的訪問狀態(tài),一方面為了方便業(yè)務實現(xiàn),另一方面為了簡化服務端的程序設計,提高訪問性能。Cookie是客戶端(也就是瀏覽器端)的技術,設置了Cookie之后,每次訪問服務端,請求中都會帶上Cookie;Session是服務端技術,在服務端存儲用戶的訪問信息。
使用Cookie傳遞信息,隨著Cookie個數(shù)增多和訪問量增大,它占用的帶寬會越來越大;使用Session保存信息,最大的弱點就是不容易在多臺服務器之間共享。
1 Cookie
通俗地講,當用戶使用HTTP訪問服務器時,服務器會將一些鍵值對信息返回給客戶端瀏覽器,并且給這些數(shù)據(jù)加一些限制條件,在符合限制條件情況下用戶下次訪問服務器時,會帶上之前設置的Cookie鍵值對信息。當該用戶輸入 URL 時,瀏覽器便會在本地硬盤上查找與該 URL 關聯(lián)的 Cookie。如果該 Cookie 存在,瀏覽器便將該 Cookie 與頁請求一起發(fā)送到您的站點。
Cookie 與網站關聯(lián),而不是與特定的頁面關聯(lián)。因此,無論用戶請求站點中的哪一個頁面,瀏覽器和服務器都將交換 Cookie 信息。用戶訪問不同站點時,各個站點都可能會向用戶的瀏覽器發(fā)送一個 Cookie;瀏覽器會分別存儲所有 Cookie。
Cookie屬性項
當前Cookie有2個版本,Version 0 和 Version 1,它們有2種設置響應頭標識,分別是"Set-Cookie"和"Set-Cookie2"。
Cookie 0屬性值

Cookie 1屬性值

Java中使用Cookie示例
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
Cookie[] cookies = request.getCookies();
String name = getCoodie(cookies, "name");
if (name == null) {
response.addCookie(new Cookie("name", "luoxn28"));
}
else {
System.out.println(name);
}
out.println("hello world");
}
public static String getCoodie(Cookie[] cookies, String key) {
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals(key)) {
return cookie.getValue();
}
}
}
return null;
}

使用Cookie的一些注意事項(以Java使用為例)
•所創(chuàng)建的Cookie的name和value不能為非ASSIC字符,如果是中文,可以通過RRLEncoder將其編碼,否則會拋出java.lang.IllegalArgumentException異常。
•多出現(xiàn)多個name和value值時,它們實在同一個"Cookie"頭中的。
•Cookies的值中可以保存除了“;”以外的標點符號。但是不能保存漢字。保存漢字會出現(xiàn)亂碼。
Cookie的一些限制
Cookie是HTTP頭中的一個字段,HTTP本身對該字段沒有限制,但是Cookie最終存儲在瀏覽器中,不同的瀏覽器對Cookie的存儲有一些限制,如下表所示:


如果試圖存儲更多 Cookie,則最舊的 Cookie 便會被丟棄。
2 Session
Session解決了Cookie增多時會增加客戶端與服務器的數(shù)據(jù)傳輸量問題,同一個客戶端與服務器交互時,不需要每次都傳回所有的Cookie值,而是只要傳回一個ID值,這個ID是客戶端第一次訪問服務器時生成的,而且每個客戶端是唯一的,這個ID通常是name為JSESSIONID的一個Cookie。
Session是如何基于Cookie工作的呢,可以是基于URL Path Parameter方式;也可以是基于Cookie,如果沒有修改Context容器中的Cookies標識,則默認也是支持的。當瀏覽器不支持Cookie功能時,瀏覽器會將用戶的SessionCookieName重寫到用戶請求的URL參數(shù)中,它的傳遞方式如/path/Servlet;name=xxx;name2=xxx2?name3=xxx3。SessionCookieName如果在web.xml中配置session-config配置項,其cookie-config下的name屬性就是這個SessionCookieName的值。如果沒有配置session-config配置項,默認的SessionCookieNamejiushi “JSESSIONID”。注意,與Session關聯(lián)的Cookie與其他Cookie并沒有什么不同。如果客戶端也支持Cookie,則Tomcat仍會解析Cookie中的Session ID,并會覆蓋URL中的Session ID。
Session如何工作
有了Session ID,服務器就可以創(chuàng)建HttpSession對象了,第一次調用request.getSession()方法,如果沒有對應的HttpSession對象,則會創(chuàng)建一個新的,并將這個對象加入到org.apache.catalina.Manager的sessions容器中保存。Manage保存所有的session生命周期,Session過期被回收,服務器關閉,Session被序列化到磁盤。注意,一個客戶端對應一個Session對象,這個對象正是保存我們創(chuàng)建的Session值的。

request.getSession()方法調用的StandardSession永遠都會存在,即使與這個客戶端關聯(lián)的Session已經過期。如果過期,則會創(chuàng)建一個新的,但是以前設置的Session值將會丟失。
3 Cookie與Session安全性比較
Cookie將保存的數(shù)據(jù)通過HTTP頭部從客戶端傳到服務端,從服務端再傳回到客戶端,所有的數(shù)據(jù)都保存在客戶端瀏覽器中,這些數(shù)據(jù)都是可以訪問到的,甚至可以通過插件添加、修改Cookie,所有Cookie的安全性是比較差的。相比較而言,Session將數(shù)據(jù)保存在服務器端,安全性高很多,只需要Cookie傳回一個Cookie ID就可以,所以Session更適合保存用戶隱私和重要的數(shù)據(jù)。
分布式Session框架
在大型互聯(lián)網應用中,單用Cookie和Session都是不可行的,因為如果使用Cookie可以很好地解決應用的分布式部署問題,大型互聯(lián)網應用系統(tǒng)一個應用有上百臺機器,而且有很多不同的應用系統(tǒng)協(xié)同工作,由于Cookie是將數(shù)據(jù)存儲在用戶瀏覽器中,用戶每次訪問都會講數(shù)據(jù)帶回到服務器,也就解決了同一個用戶的請求在不同服務器上處理而導致的Cookie不一致問題。

由于應用是一個集群,所以不能將Session都保存在每臺服務器的內存中,如果每臺服務器有幾十萬訪問用戶,服務器內存也容不下,即使容得下,也無法保證該Session同步到其他服務器中,所以共享這些Session需要將它們保存在專門的分布式緩存中,可以隨時讀取和寫入,性能要夠好滿足要求,如memcache/redis或者淘寶的開源分布式框架Tair都是很好的選擇。
表單重復提交問題
網站中有很多地方有重復提交表單問題,為了防止表單重復提交,就要標識用戶的每一次訪問請求,使得每一次訪問請求對服務端來說都是唯一的,為了標識用戶的每次請求,可以在用戶請求的表單域增加一個隱藏表單項,其值為唯一的token,如:
<form id="form" method="post"> ... <input type=hidden name="token" value="xxx"/> </form>
用戶請求表單時生成唯一的token,并且設置到該用戶的Session中,等用戶提交時檢測這個token是否和Session中保存的token一致,如果一致,說明沒有重復提交,同時把Session中的token更新成一個新的token值;否則用戶提交上來的token已經不是當前請求的合法token,提交失敗。

以上所述是小編給大家介紹的Java中Cookie和Session的那些事兒,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對腳本之家網站的支持!
相關文章
Java線上問題排查神器Arthas實戰(zhàn)原理解析
原先我們Java中我們常用分析問題一般是使用JDK自帶或第三方的分析工具如jstat、jmap、jstack、?jconsole、visualvm、Java?Mission?Control、MAT等,還有一款神器Arthas工具,可幫助程序員解決很多繁瑣的問題,感興趣的朋友一起看看吧2022-01-01
RocketMQ線程池創(chuàng)建實現(xiàn)原理詳解
這篇文章主要為大家介紹了RocketMQ線程池創(chuàng)建實現(xiàn)原理詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-12-12
Mybatis-plus如何查詢表中指定字段(不查詢全部字段)
這篇文章主要介紹了Mybatis-plus如何查詢表中指定字段(不查詢全部字段),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-07-07
詳解springboot整合ehcache實現(xiàn)緩存機制
這篇文章主要介紹了詳解springboot整合ehcache實現(xiàn)緩存機制,ehcache提供了多種緩存策略,主要分為內存和磁盤兩級,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-01-01
Java數(shù)組實現(xiàn)動態(tài)初始化的實例詳解
在本篇文章里小編給大家整理的是一篇關于Java數(shù)組實現(xiàn)動態(tài)初始化的實例詳解內容,有興趣的朋友們可以學習下。2021-10-10
IntelliJ IDEA搜索整個項目進行全局替換(有危險慎用)
今天小編就為大家分享一篇關于IntelliJ IDEA搜索整個項目進行全局替換(有危險慎用),小編覺得內容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2018-10-10
使用cmd根據(jù)WSDL網址生成java客戶端代碼的實現(xiàn)
這篇文章主要介紹了使用cmd根據(jù)WSDL網址生成java客戶端代碼的實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-03-03

