Javaweb之cookie和session

一、會話的概念

  會話可簡單理解爲:用戶開一個瀏覽器,點擊多個超鏈接,訪問服務器多個web資源,然後關閉瀏覽器,整個過程稱之爲一個會話。
  有狀態會話:一個同學來過教室,下次再來教室,我們會知道這個同學曾經來過,這稱之爲有狀態會話。

二、會話過程中要解決的一些問題

  每個用戶在使用瀏覽器與服務器進行會話的過程中,不可避免各自會產生一些數據,程序要想辦法爲每個用戶保存這些數據。

三、保存會話數據的兩種技術

3.1、Cookie機制

  Cookie是客戶端技術,程序把每個用戶的數據以cookie的形式寫給用戶各自的瀏覽器。當用戶使用瀏覽器再去訪問服務器中的web資源時,就會帶着各自的數據去。這樣,web資源處理的就是用戶各自的數據了。

3.2、Session機制

  session機制是一種服務器端的機制,服務器使用一種類似於散列表的結構(也可能就是使用散列表)來保存信息。

  當程序需要爲某個客戶端的請求創建一個session的時候,服務器首先檢查這個客戶端的請求裏是否包含了一個session標識-稱爲session id,如果已經包含一個sessionid則說明以前已經爲這個客戶創建過session,服務器就按照session id把這個session檢索出來使用(如果檢索不到,可能會新建一個,這種情況可能出現在服務端已經刪除了該用戶對應的session對象,但用戶人爲地在請求的URL後面附加上一個JSESSION的參數)。

如果客戶請求不包含session id,則服務器會爲這個客戶創建一個session並且生成一個與此session相關聯的session id,這個session id將在本次響應中返回給客戶端保存

3.3、Cookie機制和Session機制的區別

1、從存取方式上比較
Cookie中只能保存ASCII字符串,如果需要存取Unicode字符或者二進制數據,需要進行UTF-8GBK或者BASE64等方式的編碼。Cookie中也不能直接存取Java對象。若要存儲稍微複雜的信息,使用Cookie是比較困難的。
而Session中可以存取任何類型的數據,包括而不限於String、Integer、List、Map等。Session中也可以直接保存Java Bean乃至任何Java類,對象等,使用起來非常方便。可以把Session看做是一個Java容器類。
2、從隱私安全上比較
Cookie存儲在客戶端瀏覽器中,對客戶端是可見的,客戶端的一些程序可能會窺探、複製甚至修改Cookie中的內容。而Session存儲在服務器上,對客戶端是透明的,不存在敏感信息泄露的危險。
如果選用Cookie,比較好的辦法是,敏感的信息如賬號密碼等儘量不要寫到Cookie中。最好是像Google、Baidu那樣將Cookie信息加密,提交到服務器後再進行解密,保證Cookie中的信息只有自己能讀得懂。而如果選擇Session就省事多了,反正是放在服務器上,Session裏任何隱私都可以。
3、從有效期上比較
Cookie能實現信息永久的保存,只需要設置CookiemaxAge屬性爲一個很大很大的數字或者Integer.MAX_VALUE就可以了。如果不設置過期時間,則表示這個cookie生命週期爲瀏覽器會話期間,只要關閉瀏覽器窗口,cookie就消失了。這種生命期爲瀏覽會話期的cookie被稱爲會話cookie。會話cookie一般不保存在硬盤上而是保存在內存裏。

如果設置了過期時間,瀏覽器就會把cookie保存到硬盤上,關閉後再次打開瀏覽器,這些cookie依然有效直到超過設定的過期時間。

存儲在硬盤上的cookie可以在不同的瀏覽器進程間共享,比如兩個IE窗口。而對於保存在內存的cookie,不同的瀏覽器有不同的處理方式。
使用Session理論上也能實現這種效果。只要調用方法setMaxInactiveInterval(Integer. MAX_VALUE)不就可以了麼。但是由於Session依賴於名爲JSESSIONID的Cookie,而Cookie JSESSIONID的maxAge默認爲-1,只要關閉了瀏覽器該Session就會失效,因此Session不能實現信息永久有效的效果。使用URL地址重寫也不能實現。
而且如果設置Session的超時時間過長,服務器累計的Session就會越多,越容易導致內存溢出。
4、從對服務器的負擔上比較
Session是保存在服務器端的,每個用戶都會產生一個Session。如果併發訪問的用戶非常多,會產生非常多的Session,消耗大量的內存。因此像GoogleBaiduSina這樣併發訪問量極高的網站,是不太可能使用Session來追蹤客戶會話的。
而Cookie保存在客戶端,不佔用服務器資源。如果併發瀏覽的用戶非常多,Cookie是很好的選擇。對於Google、Baidu、Sina來說,Cookie也許是唯一的選擇。
5、從瀏覽器支持上比較
Cookie是需要客戶端瀏覽器支持的。如果客戶端禁用了Cookie,或者不支持Cookie,則會話跟蹤會失效。對於WAP上的應用,常規的Cookie就派不上用場了。
如果客戶端瀏覽器不支持Cookie,需要使用Session以及URL地址重寫。需要注意的是所有的用到Session程序的URL都要使用response.encodeURL(String URL)或者response.encodeRedirectURL(String URL)進行URL地址重寫,否則導致Session會話跟蹤失敗。對於WAP應用來說,Session+URL地址重寫也許是它唯一的選擇。
如果客戶端支持Cookie,則Cookie既可以設爲本瀏覽器窗口以及子窗口內有效(把maxAge設爲-1),也可以設爲所有瀏覽器窗口內有效(把maxAge設爲某個大於0的整數)。但Session只能在本瀏覽器窗口以及其子窗口內有效。如果兩個瀏覽器窗口互不相干,它們將使用兩個不同的Session。
6、從跨域名上比較
Cookie支持跨域名訪問,例如將domain屬性設置爲".helloweenvsfei.com",則以".helloweenvsfei.com"爲後綴的所有域名均可以訪問該Cookie。跨域名Cookie現在被廣泛用在網絡中,例如GoogleBaiduSina等。而Session則不會支持跨域名訪問。Session僅在他所在的域名內有效。

四、Cookie使用範例

4.1、使用cookie記錄用戶上一次訪問的時間

[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. package com.servlet.study;  
  2.    
  3. import java.io.IOException;  
  4. import java.io.PrintWriter;  
  5. import java.util.Date;  
  6. import javax.servlet.ServletException;  
  7. import javax.servlet.http.Cookie;  
  8. import javax.servlet.http.HttpServlet;  
  9. import javax.servlet.http.HttpServletRequest;  
  10. import javax.servlet.http.HttpServletResponse;  
  11. /** 
  12.  * cookie實例:獲取用戶上一次訪問的時間 
  13.  */  
  14. public classCookieDemo1 extends HttpServlet {  
  15.    
  16.    publicvoiddoGet(HttpServletRequest request, HttpServletResponse response)  
  17.             throws ServletException, IOException {  
  18.         //設置服務器端以UTF-8編碼進行輸出  
  19.         response.setCharacterEncoding("UTF-8");  
  20.         //設置瀏覽器以UTF-8編碼進行接收,解決中文亂碼問題  
  21.         response.setContentType("text/html;charset=UTF-8");  
  22.         PrintWriter out = response.getWriter();  
  23.         //獲取瀏覽器訪問訪問服務器時傳遞過來的cookie數組  
  24.         Cookie[] cookies =request.getCookies();  
  25.         //如果用戶是第一次訪問,那麼得到的cookies將是null  
  26.         if (cookies!=null) {  
  27.             out.write("您上次訪問的時間是:");  
  28.             for (int i = 0; i < cookies.length; i++) {  
  29.                 Cookie cookie = cookies[i];  
  30.                 if (cookie.getName().equals("lastAccessTime")){  
  31.                     Long lastAccessTime =Long.parseLong(cookie.getValue());  
  32.                     Date date = new Date(lastAccessTime);  
  33.                     out.write(date.toLocaleString());  
  34.                 }  
  35.             }  
  36.         }else {  
  37.             out.write("這是您第一次訪問本站!");  
  38.         }  
  39.          
  40.         //用戶訪問過之後重新設置用戶的訪問時間,存儲到cookie中,然後發送到客戶端瀏覽器  
  41.         Cookie cookie = new Cookie("lastAccessTime",System.currentTimeMillis()+"");//創建一個cookie,cookie的名字是lastAccessTime  
  42.         //將cookie對象添加到response對象中,這樣服務器在輸出response對象中的內容時就會把cookie也輸出到客戶端瀏覽器  
  43.         response.addCookie(cookie);  
  44.    }  
  45.    publicvoiddoPost(HttpServletRequest request, HttpServletResponse response)  
  46.             throws ServletException, IOException {  
  47.         doGet(request, response);  
  48.    }  
  49. }  


第一次訪問時這個Servlet時會提示這是您第一次訪問本網站,點擊瀏覽器的刷新按鈕,進行第二次訪問,此時就服務器就可以通過cookie獲取瀏覽器上一次訪問的時間了。

   在上面的例子中,在程序代碼中並沒有使用setMaxAge方法設置cookie的有效期,所以當關閉瀏覽器之後,cookie就失效了,要想在關閉了瀏覽器之後,cookie依然有效,那麼在創建cookie時,就要爲cookie設置一個有效期。如下所示:

//用戶訪問過之後重新設置用戶的訪問時間,存儲到cookie中,然後發送到客戶端瀏覽器

Cookie cookie = new Cookie("lastAccessTime",System.currentTimeMillis()+"");//創建一個cookie,cookie的名字是lastAccessTime

 //設置Cookie的有效期爲1天

 cookie.setMaxAge(24*60*60);

 //將cookie對象添加到response對象中,這樣服務器在輸出response對象中的內容時就會把cookie也輸出到客戶端瀏覽器

 response.addCookie(cookie);

  用戶第一次訪問時,服務器發送給瀏覽器的cookie就存儲到了硬盤上,這樣即使關閉了瀏覽器,下次再訪問時,也依然可以通過cookie獲取用戶上一次訪問的時間。

五、Cookie注意細節

  1. 一個Cookie只能標識一種信息,它至少含有一個標識該信息的名稱(NAME)和設置值(VALUE)。
  2. 一個WEB站點可以給一個WEB瀏覽器發送多個Cookie,一個WEB瀏覽器也可以存儲多個WEB站點提供的Cookie。
  3. 瀏覽器一般只允許存放300個Cookie,每個站點最多存放20個Cookie,每個Cookie的大小限制爲4KB。
  4. 如果創建了一個cookie,並將他發送到瀏覽器,默認情況下它是一個會話級別的cookie(即存儲在瀏覽器的內存中),用戶退出瀏覽器之後即被刪除。若希望瀏覽器將該cookie存儲在磁盤上,則需要使用maxAge,並給出一個以秒爲單位的時間。將最大時效設爲0則是命令瀏覽器刪除該cookie

 5.2、cookie中存取中文

要想在cookie中存儲中文,那麼必須使用URLEncoder類裏面的encode(String s, String enc)方法進行中文轉碼,例如:

Cookie cookie = newCookie("userName", URLEncoder.encode("Cookie測試","UTF-8"));

response.addCookie(cookie);

在獲取cookie中的中文數據時,再使用URLDecoder類裏面的decode(String s, String enc)進行解碼,例如:

URLDecoder.decode(cookies[i].getValue(),"UTF-8")

六、session使用範例

6.1、服務器是如何實現一個session爲一個用戶瀏覽器服務的?

   服務器創建session出來後,會把session的id號,以cookie的形式回寫給客戶機,這樣,只要客戶機的瀏覽器不關,再去訪問服務器時,都會帶着session的id號去,服務器發現客戶機瀏覽器帶session id過來了,就會使用內存中與之對應的session爲之服務。可以用如下的代碼證明:

[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. package com.servlet.study;  
  2.    
  3. import java.io.IOException;  
  4. import javax.servlet.ServletException;  
  5. import javax.servlet.http.HttpServlet;  
  6. import javax.servlet.http.HttpServletRequest;  
  7. import javax.servlet.http.HttpServletResponse;  
  8. import javax.servlet.http.HttpSession;  
  9.    
  10. public classSessionDemo1 extends HttpServlet {  
  11.    
  12.    publicvoiddoGet(HttpServletRequest request, HttpServletResponse response)  
  13.             throws ServletException, IOException {  
  14.    
  15.         response.setCharacterEncoding("UTF=8");  
  16.         response.setContentType("text/html;charset=UTF-8");  
  17.         //使用request對象的getSession()獲取session,如果session不存在則創建一個  
  18.         HttpSession session = request.getSession();  
  19.         //將數據存儲到session中  
  20.         session.setAttribute("data","Session測試");  
  21.         //獲取session的Id  
  22.         String sessionId = session.getId();  
  23.         //判斷session是不是新創建的  
  24.         if (session.isNew()) {  
  25.             response.getWriter().print("session創建成功,session的id是:"+sessionId);  
  26.         }else {  
  27.             response.getWriter().print("服務器已經存在該session了,session的id是:"+sessionId);  
  28.         }  
  29.    }  
  30.    
  31.    publicvoiddoPost(HttpServletRequest request, HttpServletResponse response)  
  32.             throws ServletException, IOException {  
  33.         doGet(request, response);  
  34.    }  
  35. }  


第一次訪問時,服務器會創建一個新的sesion,並且把session的Id以cookie的形式發送給客戶端瀏覽器,點擊刷新按鈕,再次請求服務器,此時就可以看到瀏覽器再請求服務器時,會把存儲到cookie中的session的Id一起傳遞到服務器端了

6.2、session對象的銷燬時機

  session對象默認30分鐘沒有使用,則服務器會自動銷燬session,在web.xml文件中可以手工配置session的失效時間,例如:

[html] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. <?xmlversionxmlversion="1.0" encoding="UTF-8"?>  
  2. <web-appversionweb-appversion="2.5"  
  3.    xmlns="http://java.sun.com/xml/ns/javaee"  
  4.    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  5.    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee  
  6.     http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">  
  7.   <display-name></display-name>  
  8.   <welcome-file-list>  
  9.    <welcome-file>index.jsp</welcome-file>  
  10.   </welcome-file-list>  
  11.   <!-- 設置Session的有效時間:以分鐘爲單位-->  
  12.     <session-config>  
  13.         <session-timeout>15</session-timeout>  
  14.     </session-config>  
  15. </web-app>  


當需要在程序中手動設置Session失效時,可以手工調用session.invalidate方法,摧毀session。

[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. HttpSession session = request.getSession();  
  2. //手工調用session.invalidate方法,摧毀session  
  3. session.invalidate();  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章