Cookie 讀寫詳解


Cookie的引文原意是“點心”,它是在客戶端訪問Web服務器時,服務器在客戶端硬盤上存放的信息,好像是服務器發送給客戶的“點心”。服務器可以根據Cookie來跟蹤客戶狀態,這對於需要區別客戶的場合(如電子商務)特別有用。

當客戶端首次請求訪問服務器時,服務器先在客戶端存放包含該客戶的相關信息的Cookie,以后客戶端每次請求訪問服務器時,都會在HTTP請求數據中包含Cookie,服務器解析HTTP請求中的Cookie,就能由此獲得關於客戶的相關信息。

 

Cookie的運行機制是由HTTP協議規定的,多數Web服務器和瀏覽器都支持Cookie。Web服務器為了支持Cookie,需具備以下功能:

·在HTTP響應結果中添加Cookie數據。

·解析HTTP請求中的Cookie數據。

瀏覽器為了支持Cookie,需要具備以下功能:

·解析HTTP響應結果中的Cookie數據。

·把Cookie數據保存到本地硬盤。

·讀取本地硬盤上的Cookie數據,把它添加到HTTP請求中。

Cookie操作

對Cookie的操作無外乎三部分:讀、分析、寫。

寫Cookie

Cookie theCookie = new Cookie(“username” , “Tom”);

response.addCookie(theCookie);

當Servlet向客戶端寫Cookie時,還可以通過Cookie類的setMaxAge(intexpiry)方法來設置Cookie的有效期。參數expiry以秒為單位,它具有以下含義:

·如果expiry大於零,就指示瀏覽器在客戶端硬盤上保存Cookie的時間為expriy秒。

·如果expiry等於零,就指示瀏覽器刪除當前Cookie。

·如果expiry小於零,就指示瀏覽器不要把Cookie保存到客戶端硬盤。Cookie僅僅存在於當前瀏覽器進程中,當瀏覽器進程關閉,Cookie也就消失。

Cookie默認的有效期為-1。對於來自客戶端的Cookie,Servlet可以通過Cookie類的getMaxAge()方法來讀取Cookie的有效期。

讀取分析客戶端Cookie

Cookie[] cookies = request.getCookies();

HttpServletRequest類的getCookies()方法返回一個Cookie數組,它包含了HTTP請求中的所有Cookie。如果在HTTP請求中沒有任何Cookie,那么getCookies()方法返回null。

對於每個Cookie對象,可調用getName()方法來獲得Cookie的名字,調用getValue()方法來獲得Cookie的值。

Cookie的使用示例

示例1

先讀取客戶端的所有Cookie,把每個Cookie的名字、值和有效期打印出來,然后向客戶端寫一個Cookie。

 

[java]  view plain  copy
 
  1. public class CookieServlet extends HttpServlet {  
  2.     private static final long serialVersionUID = 1L;  
  3.     int count = 0;  
  4.     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  
  5.         this.doPost(request, response);  
  6.     }  
  7.   
  8.     protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {  
  9.         res.setContentType("text/plain");  
  10.         PrintWriter out = res.getWriter();  
  11.         Cookie[] cookies = req.getCookies();  
  12.         if(cookies != null){  
  13.             for(int i = 0 ; i < cookies.length ; i++){  
  14.                 out.println("Cookie name:" + cookies[i].getName());  
  15.                 out.println("Cookie value:" + cookies[i].getValue());  
  16.                 out.println("Cookie maxAge:" + cookies[i].getMaxAge());  
  17.             }  
  18.         }else{  
  19.             out.println("No cookie.");  
  20.         }  
  21.         res.addCookie(new Cookie("cookieName" + count , "cookieValue" + count));  
  22.         count++;  
  23.     }  
  24. }  

 

在web.xml文件中為CookieServlet映射的URL為“/cookie”,按照下面的步驟訪問CookieServlet:

(1)           打開瀏覽器,第一次訪問CookieServlet。由於瀏覽器端此時還不存在任何Cookie,因此CookieServlet向客戶端返回“No cookie.”。

(2)           在同一個瀏覽器中第二次訪問CookieServlet。在步驟一中CookieServlet已經向客戶端寫了一個Cookie:“cookieName0=cookieValue0”,因此在瀏覽器第二次發出的HTTP請求中包含了這個Cookie,CookieServlet讀取該Cookie,並向客戶端返回該Cookie的信息,在頁面中顯示的Cookie的有效期為-1,表示該Cookie僅存在於當前瀏覽器進程中,其他瀏覽器進程無法訪問到這個Cookie。

(3)           在同一個瀏覽器中第三次訪問CookieServlet。在步驟二中CookieServlet已經向瀏覽器寫了一個Cookie:“cookieName1=cookieValue1”,CookieServlet向客戶端返回步驟一及步驟二中生成的Cookie的信息。

(4)           再打開一個新的瀏覽器,從這個瀏覽器中第一次訪問CookieServlet。由於這個瀏覽器客戶端此時還不存在任何Cookie,因此CookieServlet向客戶端返回“No cookie.”。

(5)           從第二個瀏覽器中第二次訪問Servlet。在步驟四中CookieServlet向客戶端寫了一個Cookie:“cookieName3=cookieValue3”,因此CookieServlet向客戶端返回該Cookie的信息。

示例2 對Cookie的修改和刪除

先讀取客戶端的所有的Cookie,尋找名為username的cookie,然后判斷,如果不存在就向客戶端寫入一個新的Cookie:“username=Tom”,且有效期為1小時;如果存在且值為Tom,將值改為Jack,如果存在且值為Jack,刪除該Cookie。

 

[java]  view plain  copy
 
  1. protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {  
  2.         Cookie cookie = null;  
  3.         res.setContentType("text/plain");  
  4.         PrintWriter out = res.getWriter();  
  5.         Cookie[] cookies = req.getCookies();  
  6.         if(cookies != null){  
  7.             for(int i = 0 ; i < cookies.length ; i++){  
  8.                 out.println("Cookie name:" + cookies[i].getName());  
  9.                 out.println("Cookie value:" + cookies[i].getValue());  
  10.                 if(cookies[i].getName().equals("username"))  
  11.                     cookie = cookies[i];  
  12.             }  
  13.         }else{  
  14.             out.println("No cookie.");  
  15.         }  
  16.           
  17.         if(cookie==null){  
  18.             cookie=new Cookie("username" , "Tom");  
  19.             cookie.setMaxAge(60*60);  
  20.             res.addCookie(cookie);  
  21.         }else if(cookie.getValue().equals("Tom")){  
  22.             cookie.setValue("Jack");  
  23.             res.addCookie(cookie);  
  24.         }else if(cookie.getValue().equals("Jack")){  
  25.             cookie.setMaxAge(0);  
  26.             res.addCookie(cookie);  
  27.         }  
  28.     }  

 

(1)      打開瀏覽器,第一次訪問Cookie1Servlet。由於瀏覽器端此時還不存在任何Cookie,因此Cookie1Servlet向客戶端返回“No cookie.”。

(2)      在同一個瀏覽器中第二次訪問Cookie1Servlet。在步驟一中Cookie1Servlet已經向瀏覽器端寫了一個Cookie:“username=Tom”,瀏覽器在本次HTTP請求中包含了這個Cookie,Cookie1Servlet向客戶端返回該Cookie的信息:

Cookie name:username

Cookie value:Tom

(3)      在同一個瀏覽器中第三次訪問Cookie1Servlet。在步驟二中Cookie1Servlet已經把瀏覽器端的名為“username”的Cookie的值改為“Jack”,瀏覽器在本次HTTP請求中包含了這個Cookie,Cookie1Servlet向客戶端返回修改后的Cookie的信息:

Cookie name:username

Cookie value:Jack

(4)      在同一個瀏覽器中第四次訪問Cookie1Servlet。在步驟三中Cookie1Servlet已經把瀏覽器端的名“username”的Cookie的有效期設為“0”,瀏覽器在處理步驟三中的HTTP響應結果時會刪除該Cookie。瀏覽器在本次HTTP請求中不包含任何Cookie信息,因此Cookie1Servlet向客戶端返回“No cookie”。

(5)      再打開一個新的瀏覽器,訪問Cookie1Servlet。在步驟四中Cookie1Servlet已經向瀏覽器端寫了一個Cookie:“username=Tom”,它的有效期為1小時,因此瀏覽器會把它保存到硬盤,其他瀏覽器也能反問這個Cookie。新打開的瀏覽器在HTTP請求中包含了這個Cookie,Cookie1Servlet向客戶端返回該Cookie的信息。

假定在Tomcat服務器A上有一個app1應用和一個app2應用,在Tomcat服務器B上有一個app3應用。用戶會通過一個瀏覽器進程訪問app1、app2、app3應用。

假定app1應用中的一個Web組件X在瀏覽器上保存了一個Cookie,當瀏覽器再次請求訪問app1、app2和app3應用中的其他Web組件時,瀏覽器是否會把Cookie添加到HTTP請求中,從而讓這些Web組件能夠讀取該Cookie呢?

在默認情況下,處於安全的原因,只有app1應用中的Web組件能讀取該Cookie。如果希望改變Cookie的共享范圍,那么app1應用中的Web組件X在寫Cookie時,可以通過setPath(Stringpath)和setDodomain(String domain)方法來設置Cookie的path和domain屬性。

(1)      讓同一個Tomcat服務器A中的app1應用和app2應用共享Cookie。app1應用中的Web組件X的寫Cookie的代碼:

Cookie cookie = new Cookie(“username” , “Tom”);

cookie.setPath(“/”);

res.addCookie(cookie);

以上serPath()的參數為“/”,表示Tomcat服務器的根路徑,因此同一個Tomcat服務器中的所有Web應用可以共享上述Cookie。

(2)      只能讓Tomcat服務器A中的app2應用訪問該Cookie。app1應用中的Web組件X的寫Cookie的代碼如下;

Cookie cookie = new Cookie(“username” , “Tom”);

cookie.setPath(“/app2/”);

res.addCookie(cookie);

以上setPath()的參數為“/app2/”,因此只有Tomcat服務器A中的app2應用可以訪問該Cookie,app1應用也無法訪問該Cookie。

(3)      只讓Tomcat服務器A中的app1應用中的位於“/sub”子路徑下的Web組件訪問Cookie。app1中應用中的Web組件X的寫Cookie代碼:

Cookie cookie = new Cookie(“username” , “Tom”);

cookie.setPath(“/app1/sub”);

res.addCookie(cookie);

(4)      讓Tomcat服務器B中的所有Web應用訪問Cookie,假定Tomcat服務器B的域名為www.cat.com。app1應用中的Web組件X的寫Cookie的代碼:

Cookie cookie = new Cookie(“username” , “Tom”);

cookie.setDomain(“.cat.com”);

res.addCookie(cookie);

模擬taobao等網站的廣告推廣

類似的網站在客戶瀏覽信息時,會將瀏覽歷史數據保存在客戶端,在下次客戶打開網站時,向客戶推廣最近瀏覽過的商品信息。

頁面中的每個連接代表一個商品分類,在點擊連接時通過AddCookieServlet向客戶端保存Cookie:“itemsNum:6923384801114”:

[java]  view plain  copy
 
  1. public class AddCookieServlet extends HttpServlet {  
  2.     private static final long serialVersionUID = 1L;  
  3.          
  4.     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  
  5.         this.doPost(request, response);  
  6.     }  
  7.   
  8.     protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {  
  9.         Cookie cookie = null;  
  10.         res.setContentType("text/html;charset=utf-8");  
  11.         PrintWriter out = res.getWriter();  
  12.         out.println("<html><head><title>商品列表</title></head><body><ul><li>");  
  13.         out.println("<a href=\"addCookie?itemNum=6923384801114\">服裝</a></li><li>");  
  14.         out.println("<a href=\"addCookie?itemNum=6923384801113\">電器</a></li><li>");  
  15.         out.println("<a href=\"addCookie?itemNum=6923384801112\">禮品</a></li><li>");  
  16.         out.println("<a href=\"addCookie?itemNum=6923384801111\">娛樂</a></li></ul>");  
  17.         Cookie[] cookies = req.getCookies();  
  18.         if(cookies != null){  
  19.             for(int i = 0 ; i < cookies.length ; i++){  
  20.                 if(cookies[i].getName().equals("itemsNum")){  
  21.                     out.println("你可能需要:商品編號[" + cookies[i].getValue() + "]");  
  22.                     cookie = cookies[i];  
  23.                 }  
  24.             }  
  25.         }else{  
  26.             out.println("No cookie.");  
  27.         }  
  28.           
  29.         String itemNum = req.getParameter("itemNum");  
  30.         if(itemNum!=null){  
  31.             cookie=cookie==null?new Cookie("itemsNum" , itemNum):cookie;  
  32.             cookie.setValue(itemNum);  
  33.             cookie.setMaxAge(60*60*24*7);  
  34.             res.addCookie(cookie);  
  35.         }  
  36.         out.println("</body></html>");  
  37.     }  
  38. }  

打開瀏覽器訪問http://localhost:8080/webdemo/addCookie。初始頁面為:

點擊其中的一個連接,然后再打開另一個瀏覽器或是關閉當前網頁再打開上面的連接,發現頁面會顯示上次瀏覽的商品編號:

此類應用可以根據用戶的使用,動態設置推廣信息、客戶個性化喜好等,還可以在邏輯中增加判斷,查看客戶隔了多長時間再次訪問該網站。

使用Cookie模擬自動登錄

用戶登錄一次后選擇自動登錄,在下次登錄該網站時無需登錄步驟,就可直接進入網頁。

首先應該有一個過濾器判斷用戶是否設置了自動登錄,如果設置了自動登錄則從Cookie中讀取數據直接登錄,進入網站。創建過濾器,並注冊到應用中:

 

[java]  view plain  copy
 
  1. public class LoginFilter implements Filter {  
  2.     public void init(FilterConfig fConfig) throws ServletException {}  
  3.     public void destroy() {}  
  4.     public void doFilter(ServletRequest reqest, ServletResponse response,  
  5.             FilterChain chain) throws IOException, ServletException {  
  6.         HttpServletRequest req = (HttpServletRequest) reqest;  
  7.         HttpServletResponse res = (HttpServletResponse) response;  
  8.         if (!req.getRequestURI().endsWith("login.html")&&!req.getRequestURI().endsWith("loginServlet")) {  
  9.             HttpSession session = req.getSession();  
  10.             User sessionUser = (User) session.getAttribute("user");  
  11.             if (sessionUser == null) {  
  12.                 Cookie[] cookies = req.getCookies();  
  13.                 if (cookies != null) {  
  14.                     for (int i = 0; i < cookies.length; i++) {  
  15.                         if (cookies[i].getName().equals("login")) {  
  16.                             String loginInfo = cookies[i].getValue();  
  17.                             String[] infos = loginInfo.split("&", 2);  
  18.                             String username = infos[0];  
  19.                             String password = infos[1];  
  20.                             User user = new User(username, password);  
  21.                             session.setAttribute("user", user);  
  22.                             chain.doFilter(req, res);  
  23.                             return;  
  24.                         }  
  25.                     }  
  26.                 }  
  27.                 res.sendRedirect("login.html");  
  28.                 return;  
  29.             }  
  30.         }  
  31.         chain.doFilter(reqest, response);  
  32.     }  
  33. }  

 

在該過濾器中先從session中取user值,如果沒有則判斷該客戶端是否有名為login的Cookie,如果有表示該用戶設置了自動登錄,且已經保存了登錄信息(即已經登錄過)則直接跳轉到目標頁面,如果以上條件都沒有滿足,則跳轉至登錄頁面。web.xml文件中Filter的配置代碼為:

 

[html]  view plain  copy
 
  1. <filter>  
  2.     <filter-name>LoginFilter</filter-name>  
  3.     <display-name>LoginFilter</display-name>  
  4.     <filter-class>filter.LoginFilter</filter-class>  
  5.   </filter>  
  6.   <filter-mapping>  
  7.     <filter-name>LoginFilter</filter-name>  
  8.     <url-pattern>*</url-pattern>  
  9.   </filter-mapping>  

 

然后創建登錄頁面:

[html]  view plain  copy
 
  1. <!DOCTYPE html>  
  2. <html>  
  3. <head>  
  4. <meta charset="UTF-8">  
  5. <title>登錄</title>  
  6. </head>  
  7. <body>  
  8.     <form name = "loginForm" method="POST" action="loginServlet">  
  9.         <table>  
  10.             <tr>  
  11.                 <td><div align="right">用戶名:</div></td>  
  12.                 <td><input type="text" name="username"></td>  
  13.             </tr>  
  14.             <tr>  
  15.                 <td><div align="right">密碼:</div></td>  
  16.                 <td><input type="password" name="password"></td>  
  17.             </tr>  
  18.             <tr>  
  19.                 <td><input type="checkbox" name="autoLogin">自動登錄</td>  
  20.             </tr>  
  21.             <tr>  
  22.                 <td><input type="submit" name="submit" value="登錄"></td>  
  23.                 <td><input type="reset" name="reset" value="重置"></td>  
  24.             </tr>  
  25.         </table>  
  26.     </form>  
  27. </body>  
  28. </html>  

該登錄頁面請求Servlet,在Servlet中進行數據的校驗等工作:

[java]  view plain  copy
 
  1. public class LoginServlet extends HttpServlet {  
  2.     private static final long serialVersionUID = 1L;  
  3.     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  
  4.         this.doPost(request, response);  
  5.     }  
  6.   
  7.     protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {  
  8.         boolean auto = req.getParameter("autoLogin")!=null&&req.getParameter("autoLogin").equals("on")?true:false;  
  9.         String username = req.getParameter("username");  
  10.         String password = req.getParameter("password");  
  11.         User user = new User(username , password);  
  12.         HttpSession session = req.getSession();  
  13.         session.setAttribute("user", user);  
  14.         Cookie cookie = null;  
  15.         Cookie[] cookies = req.getCookies();  
  16.         if(cookies !=null){  
  17.             for(int i = 0 ; i < cookies.length ; i++){  
  18.                 if(cookies[i].getName().equals("login")){  
  19.                     cookie = cookies[i];  
  20.                     cookie.setValue(username + "&" + password);  
  21.                 }  
  22.             }  
  23.         }  
  24.         if(cookie == null){  
  25.             cookie = new Cookie("login" , username + "&" + password);  
  26.         }  
  27.         if(auto){  
  28.             cookie.setMaxAge(60*60*24*7);  
  29.         }else{  
  30.             cookie.setMaxAge(0);  
  31.         }  
  32.         res.addCookie(cookie);  
  33.         res.sendRedirect("hello.jsp");  
  34.     }  
  35. }  

在該Servlet中完成的工作是將用戶信息保存至session並根據邏輯判斷操作Cookie。登錄成功后頁面跳轉至歡迎頁面hello.jsp:

 

[html]  view plain  copy
 
  1. <%@ page language="java" contentType="text/html; charset=utf-8"  
  2.     pageEncoding="utf-8" import="helloworld.bean.User"%>  
  3. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">  
  4. <html>  
  5. <head>  
  6. <meta http-equiv="Content-Type" content="text/html; charset=utf-8">  
  7. <title>hello</title>  
  8. <%User user = (User)session.getAttribute("user"); %>  
  9. </head>  
  10. <body>  
  11.     <b>你好:<%=user.getUsername() %></b>  
  12. </body>  
  13. </html>  

 

在保存用戶信息時使用到一個簡單的JavaBean:User。

以上就是該實驗中用到的頁面。按照以下步驟進行訪問:

(1)          啟動項目后,打開瀏覽器訪問項目中的任意頁面。如:http://localhost:8080/webdemo/hello.jsp,發現會被攔截到登錄頁面,輸入登錄信息,此時不勾選自動登錄,點擊登錄,頁面跳轉至hello.jsp。

(2)          關閉瀏覽器再打開並訪問http://localhost:8080/webdemo/hello.jsp,被攔截到登錄頁面。此時填寫登錄信息后勾選自動登錄,登錄成功后關閉瀏覽器。

(3)          打開同一瀏覽器,繼續訪問http://localhost:8080/webdemo/hello.jsp,此時發現沒有被攔截,原因是上一步中向客戶端寫了一個Cookie,打開瀏覽器並訪問時,程序讀取到用戶信息直接放入session,完成了自動登錄的功能。

訪問http://localhost:8080/webdemo/login.html.。此時不勾選自動登錄,登錄成功后,重復步驟一、二,自動登陸功能已經取消。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM