会话之cookie

在登录某个网站时,比如登录163邮箱的网站,界面中有个十天免登陆的选项,先不勾选该选项,登录成功之后关闭浏览器或重启电脑,当再次访问163邮箱时会提示用户登录,这说明http协议是无状态的,在不同的请求之间是无法进行数据传递的。

而当勾选了十天免登陆的选项并登录成功之后,关闭浏览器或者重启电脑,之后再次访问163邮箱时就会自动登录了。这说明用户登录的一些信息保存到了该电脑的硬盘中(默认会存在浏览器的缓存中,可以设置保存在硬盘上),当访问163邮箱网站时,浏览器会将这些数据发送到服务器,从而实现了自动登录的功能,客户端电脑中用于保存这数据的资源,称为cookie。

用户在勾选十天免登陆的选项并登录成功之后,由服务器生成 Cookie,并将其封装到响应头中,以响应的形式发送给浏览器。浏览器接收到这个响应后,将 Cookie 保存到硬盘中。当浏览器再次发送同类请求后,在请求中会携带保存在硬盘的Cookie数据,发送到服务端,由服务器对解析该Cookie。
Cookie 技术并不是 JavaWeb 开发专属技术,而是属于 Web 开发的技术,是所有 Web 开
发语言均支持的技术。Cookie 是由若干键值对构成,这里的键一般称为 name,值称为 value。 Cookie 中的键值对均为字符串。
总的来说cookie的作用就是在客户端存储一些数据,当浏览器再次请求某个服务器时会携带这些数据从而提供更好的用户体验。

cookie技术

删除cookie
通过火狐浏览器可以查看cookie,点击浏览器右上角的三个横杠–>选项–>隐私–>移除单个cookie,在这个界面中可以删除单个cookie也可以删除全部cookie,删除后,再次登录163网站时会提示输入用户名和密码。在其他浏览器中点击清空浏览器数据之后,也可以删除cookie。

注意:不同的web服务器在客户端所生成的cookie之间是不能相互访问和共享的。

cookie的禁用
浏览器是可以禁用 Cookie 的,即浏览器不接收服务器发送来的 Cookie。现在的很多网站,若浏览器禁用了 Cookie,则将无法访问。火狐浏览器中对于 Cookie 的禁用,是在火狐浏览器的“打开菜单/选项”的“隐私”标签中。不勾选“接受来自站点的 Cookie”,则表示禁用 Cookie。下面代码可以检测出浏览器是否禁用cookie:


if(navigator.cookieEnabled == true){
		alert("支持cookie");
	}else{
		alert("cookie已被禁用");
	}

cookie小知识

  • 一个WEB站点可以给一个WEB浏览器发送多个Cookie,一个WEB浏览器也可以存储多个WEB站点提供的Cookie。
  • 浏览器一般只允许存放300个Cookie,每个站点最多存放20个Cookie,每个Cookie的大小限制为4KB。
  • 如果创建了一个cookie,并将他发送到浏览器,默认情况下它是一个会话级别的cookie(即存储在浏览器的内存中),用户退出浏览器之后即被删除。若希望浏览器将该cookie存储在磁盘上,则需要使用maxAge,并给出一个以秒为单位的时间。将最大时效设为0则是命令浏览器删除该cookie。
  • 删除cookie时,path必须一致,否则不会删除

在javax.servlet.http包下有个名为Cookie的类,通过该类就可以向客户端设置cookie数据了。

cookie的默认绑定路径
创建一个servlet:

package com.monkey1024.servlet;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Cookie的默认绑定路径
 * 
 */
public class CookieTest01 extends HttpServlet {
    private static final long serialVersionUID = 1L;


    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //创建cookie,第一个参数类似map的key,第二个参数类似map的value,不能存中文
        Cookie cookie1 = new Cookie("username","monkey1024");
        Cookie cookie2 = new Cookie("password","123456");

        //将Cookie添加到相应中
        response.addCookie(cookie1);
        response.addCookie(cookie2);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}

在web.xml中将上面的servlet的url-pattern设置为:/test/cookie01
访问该servlet时,可以通过fiddler中看到响应头中携带了之前设置的cookie信息。此时两个cookie与默认资源路径http://localhost:8080/07-03-cs/test 进行了绑定,也就是url-pattern中的上一级路径,当再次访问路径包含以上资源路径的url时,会自动将cookie放到请求头中向服务器发出请求。

设置绑定路径
cookie除了默认绑定之外我们还可以手动设置其绑定路径:

package com.monkey1024.servlet;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Cookie的手动绑定路径
 * 
 */
public class CookieTest02 extends HttpServlet {
    private static final long serialVersionUID = 1L;


    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //创建cookie
        Cookie cookie1 = new Cookie("username","monkey1024");
        Cookie cookie2 = new Cookie("password","123456");

        //手动设置绑定路径
        cookie1.setPath("/aaa");
        cookie2.setPath("/aaa");

        //将Cookie添加到相应中
        response.addCookie(cookie1);
        response.addCookie(cookie2);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}

此时会将绑定路径设置为:http://localhost:8080/07-03-cs/aaa 即访问的url中包含该路径时才会携带cookie数据。

设置cookie的有效时长
默认情况下, Cookie 是保存在浏览器的缓存中的,关闭浏览器后Cookie也就消失了。
开发者可以通过设置Cookie的有效时长,将Cookie写入到客户端硬盘文件中。
可以通过下面的方法设置有效时长
public void setMaxAge(int expiry)
其中expiry的单位为秒,整型。

  • 大于 0,则表示要将 Cookie 写入到硬盘文件中;
  • 小于 0,则表示 Cookie 存放在浏览器缓存中,与不设置时长等效;
  • 等于 0,则表示 Cookie产生后直接失效。
package com.monkey1024.servlet;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Cookie的失效时间
 * 
 */
public class CookieTest03 extends HttpServlet {
    private static final long serialVersionUID = 1L;


    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //创建cookie
        Cookie cookie1 = new Cookie("username","monkey1024");
        Cookie cookie2 = new Cookie("password","123456");

        //手动设置绑定路径
        cookie1.setPath("/aaa");
        cookie2.setPath("/aaa");

        //设置cookie的失效时间
        cookie1.setMaxAge(60 * 60);//一小时
        cookie2.setMaxAge(60 * 60 * 24);//一天

        //将Cookie添加到相应中
        response.addCookie(cookie1);
        response.addCookie(cookie2);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}

服务器端获取请求的cookie
在 HttpServletRequest 中有一个方法getCookies(),专门用于读取请求中所携带的 Cookie 数据,该方法的返回值类型是Cookie数组。

package com.monkey1024.servlet;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 接收客户端请求中携带的Cookie
 * 
 */
public class CookieReceive extends HttpServlet {
    private static final long serialVersionUID = 1L;


    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Cookie[] cookie = request.getCookies();
        for(Cookie c : cookie){
            System.out.println("name="+c.getName());
            System.out.println("value="+c.getValue());
        }
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}

练习

1.实现获取用户上一次访问时间的功能,即当用户访问服务器,如果是非第一次访问的话,需要将上一次访问服务器的时间给用户显示出来。

2.实现十天内免登陆的功能,当用户成功登陆后,十天内可以自动登录。用户名和密码直接写在代码中即可。

答案

1.分析:
当用户第一次访问服务器时,将时间记录下来并放到cookie中,用户第二次访问时,会将该cookie发送到服务器,服务器拿到后就可以获取到上次访问的时间了,将上次访问的时间响应给浏览器并将新的访问时间放到cookie中。

代码:

package com.monkey1024.servlet;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 获取用户的最后访问时间
 * 
 */
public class LastVisitTime extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        //获取客户端的所有Cookie对象
        Cookie[] cookies = request.getCookies();
/*
        //如果等于null则说明是第一次访问
        for (int i = 0;cookies!=null && i < cookies.length; i++) {
            if("lastVisitTime".equals(cookies[i].getName())){//找到name为lastVisitTime的cookie
                long l = Long.parseLong(cookies[i].getValue());//把Cookie中的value取出
                out.write("你的最后访问时间为:"+new Date(l).toLocaleString());//yyyy-MM-dd
            }
        }

        //创建cookie,
        Cookie cookie = new Cookie("lastVisitTime",System.currentTimeMillis()+"");
*/
// 如果等于null则说明是第一次访问
       if (cookies == null) {
          out.write("第一次访问");
       } else {
          for (int i = 0; i < cookies.length; i++) {
             if ("lastVisit".equals(cookies[i].getName())) {// 找到name为lastVisitTime的cookie
                out.write("你的最后访问时间为:" + cookies[i].getValue());
              }
          }
        }
 
       //使用jdk8中的LocalDateTime
       LocalDateTime currentTime = LocalDateTime.now();
       //不能有空格
       //DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
       DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd/HH:mm:ss");
       // 创建cookie
       Cookie cookie = new Cookie("lastVisit", currentTime.format(formatter));
        //设置cookie的有效时间,单位是秒
        cookie.setMaxAge(60*60);//保存时间为1小时
        //把cookie信息写回到客户端
        response.addCookie(cookie);

    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}

2.分析:
用户登录成功之后将用户名和密码放到cookie中,当用户下次访问服务器时获取cookie中的用户名和密码与正确的用户名和密码做匹配,如果一致则直接登录成功。

代码:
第一次登录时向浏览器响应表单数据,LoginServlet

package com.monkey1024.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 用户登录
 */
public class LoginServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        request.setCharacterEncoding("UTF-8");

        String userName = "";
        String password = "";
        //得到客户端保存的Cookie数据
        Cookie[] cookies = request.getCookies();
        for (int i = 0;cookies!=null && i < cookies.length; i++) {
            if("userName".equals(cookies[i].getName())){
                userName = cookies[i].getValue();
            }
            if("password".equals(cookies[i].getName())){
                password = cookies[i].getValue();
            }
        }

        //与cookie中的用户名和密码做匹配
        if("admin".equals(userName) && "123456".equals(password)){
            out.write("登录成功!");
        }else{
            out.write("<form action='/servlet/doLogin' method='post'>");
            out.write("用户名:<input type='text' name='userName' /><br/>");
            out.write("密码:<input type='password' name='password'/><br/>");
            out.write("<input type='checkbox' name='remember' />十天免登陆<br/>");
            out.write("<input type='submit' value='登录'/><br/>");
            out.write("</form>");

        }


    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}

登录成功后将用户名和密码放入cookie中:

package com.monkey1024.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 登录
 */
public class DoLoginServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        //获取表单数据
        String userName = request.getParameter("userName");
        String password = request.getParameter("password");
        String remember = request.getParameter("remember");

        Cookie cookie1 = new Cookie("userName", userName);
        Cookie cookie2 = new Cookie("password", password);
        cookie1.setPath("/");
        cookie2.setPath("/");
        if("admin".equals(userName)&&"123456".equals(password)){
            if(remember!=null){
                cookie1.setMaxAge(60 * 60 * 240);//设置Cookie的有效保存时间为十天
                cookie2.setMaxAge(60 * 60 * 240);
                response.addCookie(cookie1);//将Cookie写回到客户端
                response.addCookie(cookie2);
            }
            out.write("登录成功!");
        }else{
            out.write("登录失败!");
            //设置2秒跳到重新登录
            response.setHeader("refresh", "2;url=/servlet/login");
        }

    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}