• 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.。此时不勾选自动登录,登录成功后,重复步骤一、二,自动登陆功能已经取消。

  • 相关阅读:
    Mysql 怎么限制 IP 访问?
    LA2965 n个数中选出最多个数异或和为0
    UVALive 2678 大于s的最短子序列和
    UVA 1193 区间相关(greedy)
    UVA 11992 线段树
    UVA 1400 线段树
    NBUT 1120 线段树
    最大连续区间和的算法总结(转)
    hiho 1015 KMP
    hiho#1128 : 二分·二分查找
  • 原文地址:https://www.cnblogs.com/tanzq/p/8075473.html
Copyright © 2020-2023  润新知