Servlet笔记(6):Cookie详解

HTTP协议是无状态的的协议。一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接。Cookie和Seesion,就是这样的机制,可以弥补HTTP协议无状态的不足

Cookie是客户端技术,程序把每个客户的数据以Cookie的形式写给用户各自的浏览器。当用户浏览器再去访问服务器中的web资源时,就会带着各自的数据去。这样web资源处理的就是用户各自的数据了

Session是服务器端技术,服务器在运行时可以为每个用户的浏览器创建一个其独享的Session对象,由于Session为用户浏览器独享,所以用户在访问服务器的web资源时,可以把各自的资源放在各自的Session中,当用户再去访问服务器中的其他web资源时,其他web资源再从用户各自的Session中取出数据为用户服务

Cookie基础

工作原理

HTTP是一种无状态的协议,服务器单从网络连接上无从知道客户的身份。Cookie就像是给客户端颁发的一个通行证。每个客户浏览器一个,无论谁访问必须携带自己的通行证。这样服务器就能从通行证上确认客户身份了

基本知识

  1. Cookie 是保存在客户端的内容,每个浏览器有各自的编号,区分浏览器,信息不共享
  2. 写入的信息只能是文本文档。不支持中文,如要支持,必须重新转码
  3. 客户端可以阻止服务器写入 Cookie
  4. Cookie 不能跨域名。服务器只能拿自己的web应用写入的东西
  5. 浏览器的Cookie数量是有限的,大概是30-50个,每个为4K左右,每个浏览器各有不同

实现

  1. 客户端请求服务器,可以使用 response 对象 向客户端浏览器颁发一个Cookie。客户端会把Cookie保存起来。当浏览器再去访问该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查Cookie,以此来辨认用户状态。服务器还可以根据需要修改 Cookie 的内容
  2. 可以在浏览器地址栏输入 javascript:alert(document.cookie) 获取所有的 Cookie 信息

Cookie操作

基本知识

  1. java中把Cookie封装成 javax.servlet.http.Cookie 类。服务器通过操作Cookie类对象对客户端Cookie进行操作
  2. Cookie对象使用 key-value 属性对的形式保存用户状态。一个 request 或者 response 同时使用多个Cookie
  3. 创建Cookie, 如果key和value为中文(Unicode字符),需要使用 URLEncoder 进行编码。如果为二进制,则需要使用Base64编码
// 1-创建Cookie
String key = "key";
String value = "cookie";
Cookie cookie = new Cookie(key, value);
System.out.println(cookie.getName());

// 1-2 创建中文, 使用URLEncoder编码 和 URLDecoder解码
Cookie cookieChina = new Cookie(URLEncoder.encode("中文", "UTF-8"), URLEncoder.encode("中文", "UTF-8"));
System.out.println(cookieChina); 
  1. 向客户端设置Cookie : response.addCookie(Cookie cookie)
  2. 获取客户端的Cookie : Cookie[] cookies = request.getCookies()(以Cookie[]数组形式返回)
  3. 获取Cookie 的name和value: String tName = Cookie.getName(); String tValue = Cookie.getValue()
// 3-从客户端获取
Cookie[] cookies = req.getCookies();
if (cookies != null && cookies.length < 0) {
    for (Cookie tCookie : cookies) {
        String tName = tCookie.getName();
        String tValue = tCookie.getValue();
        int maxAge = tCookie.getMaxAge();
        System.out.println("Cookie的name : " + tName + " | Cookie的value : " + tValue + " | Cookie的有效期:  " + maxAge);
    }
}
  1. 设置Cookie的时间 : cookie.setMaxAge(maxAge); 值的类型
  • 正数:表示Cookie在maxAge之后失效,cookieChina.setMaxAge(Integer.MAX_VALUE)-永久有效
  • 负数(-1):临时Cookie,浏览器关闭即失效,不保存。-1是默认值
  • 0-删除该Cookie。Cookie没有删除的方法,可以设置maxage为0;修改Cookie: 可以添加一个同名的Cookie用于覆盖前一个来修改Cookie
// 4-Cookie的删除与修改
Cookie cookie2 = new Cookie("time", "201401008");
// 删除Cookie,设置 setMaxAge =0 即可删除
cookie2.setMaxAge(0);
resp.addCookie(cookie2);
// 使用同名Cookie, 修改前一个 cookie 的作用
resp.addCookie(new Cookie("time", "20150909"));

image

  1. Cookie的域名: Domain属性(IE是禁止的,会有安全问题)
  • Cookie具有不可跨域名性。www.gogle.com 和 www.baidu.com不可交互Cookie。同一域名下两个二级域名 如 http://www.baidu.comhttp://music.baidu.com 也 不同交互使用Cookie。如果想所有的 baidu.com 名下的二级域名都可以使用该 Cookie, 需要设置Domain属性
  • Domain属性,必须以(“.”)开始。另外,name相同但是domain 不同的两个Cookie是两个不同的Cookie
  • 如果想要两个域名完全不同的网站共有 Cookie, 可以生成两个Cookie, domain属性分别为两个域名,输出到客户端
// 5-Cookie的域名
Cookie cookie3 = new Cookie("time", "201401008");
//设置域名,意思是所有 `baidu.com`下的二级域名都可以访问。必须以“.”开始
cookie3.setDomain(".baidu.com");
//设置所有路径都可以使用
cookie3.setPath("/");
//设置有效期
cookie3.setMaxAge(Integer.MAX_VALUE);
resp.addCookie(cookie3);
  1. Cookie的路径: path属性
  • path属性决定了访问Cookie的路径,即contextPath路径。例如,如果只允许/JavaWeb/下的程序使用Cookie,可以这么写/Javaweb/
  • path属性必须以“/XXX/”这种形式,当只有 / 时,表示所有路径都可以访问该Cookie
  • 一个Servlet/JSP 设置的cookie 只能被与这个Servlet/JSP在同一路径下或子路径下的Servlet/JSP访问。父路径和其他路径无法获取。如sesson/test/b.jsp可以获取到路径session/的 Cookie,而不能获取/session/b/的Cookie
  • 这边的路径不是指文件的存放真实路径,而是指url路径,是指<url-pattern>设置的路径
// 6-Cookie的路径  
Cookie cookie4 = new Cookie("time","201401008");  
cookie4.setPath("/Javaweb/");//只有Javaweb/下的可以访问  
response.addCookie(cookie4); 
  1. Cookie的安全属性:secure属性
    如果不希望Cookie在HTTP等非安全协议中传输,可以设置cookie的secure属性属性为true。浏览器只会在HTTPS和SSL等安全协议中传输此类Cookie
// 7-Cookie的安全属性  
Cookie cookie5 = new Cookie("time","201401008");  
cookie5.setSecure(true); //true,在HTTP中无法获取本Cookie 

JS操作Cookie

原生JS
  1. 格式:在js中Cookie的格式:account=111; ssid=222; JSESSIONID=7E99EBDC3CA63AB849D1493FBCCC5159,类似于map类型
  2. 获取:document.cookie获取所有的Cookie
  3. 获取单个固定的Cookie,可以自己封装方法
/** 
 * 获取Cookie 
 */  
var getCookie = function(name) {  
    var str = document.cookie;  
    if (!str || str.indexOf(name + "=") < 0)  
        return;  
    var cookies = str.split("; ");  
    for (var i = 0; i < cookies.length; i++) {  
        var cookie = cookies[i];  
        if (cookie.indexOf(name + "=") == 0) {  
            var value = cookie.substring(name.length + 1);  
            return decodeURI(value);  
        }  
    }  
};
  1. 创建Cookie的方法,我们也可以封装成一个方法
/** 
 * 设置Cookie 
 */  
var setCookie = function(name, value) {  
    // document.cookie = name + "=" + encodeURI(value);  
    var expires = (arguments.length > 2) ? arguments[2] : null;  
    var path = (arguments.length > 3) ? arguments[3] : null;  
    var domain = (arguments.length > 4) ? arguments[4] : null;  
    var secure = (arguments.length > 5) ? arguments[5] : false;  
    document.cookie = name  
            + "="  
            + encodeURI(value)  
            + ((expires == null) ? "" : ("; expires=" + expires  
                    .toGMTString()))  
            + ((path == null) ? "" : ("; path=" + path))  
            + ((domain == null) ? "" : ("; domain=" + domain))  
            + ((secure == true) ? "; secure" : "");  
};
Jquery 操作Cookie
  1. 需要下载 jquery.cookie.js
  2. 简单设置Cookie : 设置一个name-Cookie的名字,value-Cookie的值
$.cookie("name", "value"); 
  1. 设置其他参数
//设置完整的cookie  
$.cookie("name", "sam-sho",{  
                            expires : 10,//有效期,单位为天  
                            path : "/",  
                            domain : "jquery.com"  
                            secrue : true  
                            }); 
  1. 读取Cookie :读取名字为sam的Cookie
$.cookie("sam")  
  1. 删除Cookie :删除名称为 sam 的Cookie,只要把value设置成null。注意:必须使用与之前设置的相同的路径(path)和域名(domain),才能正确删除
$.cookie("sam",null);   

Cookie 实际案例

永久登录

  1. LoginCookieServlet: 负责记录Cookie的servlet。Post提交表单后,servlet把写两个cookie写到客户端。一是账户的cookie,另一个是账户加密后的cookie。然后重定向到CheckCookieServlet,校验。一定要用重定向,确保客户端使用两次请求。由于加密的key是服务器独有的,是安全的
public class LoginCookieServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;
    /**
     * 密钥, 可以放配置文件
     */
    private static final String KEY = ":https://sam-blog.gitee.io/";


    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    /**
     * post方法访问,处理永久登录
     */
    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");

        String action = request.getParameter("action");

        if ("login".equals(action)) {

            String account = request.getParameter("account");
            int timeout = new Integer(request.getParameter("timeout"));

            // 把帐号连同密钥使用MD5后加密后保存, 这边加密略
            String ssid = account + KEY;

            // 把帐号保存到Cookie中 并控制有效期
            // 中文需要编码
            Cookie accountCookie = new Cookie("account", account);
            accountCookie.setMaxAge(timeout);

            // 把加密结果保存到Cookie中 并控制有效期
            Cookie ssidCookie = new Cookie("ssid", ssid);
            ssidCookie.setMaxAge(timeout);
            // 账户Cookie
            response.addCookie(accountCookie);
            // 加密后账户的Cookie
            response.addCookie(ssidCookie);

            System.out.println(accountCookie.getName() + "++++++++" + accountCookie.getValue());
            System.out.println(ssidCookie.getName() + "+++++++" + ssidCookie.getValue());

            // 重定向到校验servlet
            // 使用两个request,这样访问到校验的request就带有了本次response写入的cookie。
            response.sendRedirect(this.getServletContext().getContextPath() + "/checkCookieServlet");
            return;
        }
    }
}

  1. LoginOutCookieServlet:注销的servlet,负责删除cookie。然后校验,其实可以和LoginCookieServlet进行合并
if ("logout".equals(action)) {

    // 删除Cookie中的帐号
    Cookie accountCookie = new Cookie("account", "");
    accountCookie.setMaxAge(0);

    // 删除Cookie中的加密结果
    Cookie ssidCookie = new Cookie("ssid", "");
    ssidCookie.setMaxAge(0);

    response.addCookie(accountCookie);
    response.addCookie(ssidCookie);

    // 重定向到校验servlet
    response.sendRedirect(this.getServletContext().getContextPath() + "/checkCookieServlet");
    return;
}
  1. CheckCookieServlet:负责校验 Cookie
public class CheckCookieServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;
    /**
     * 密钥, 可以放配置文件
     */
    private static final String KEY = ":https://sam-blog.gitee.io/";

    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    /**
     * 校验
     */
    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");

        boolean loggin = false;
        String account = null;
        String ssid = null;

        // 获取Cookie中的account与ssid
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            System.out.println("所有的Cookies : " + Arrays.asList(cookies));

            for (Cookie cookie : cookies) {
                if ((cookie.getName()).equals("account")) {
                    account = cookie.getValue();
                }
                if ((cookie.getName()).equals("ssid")) {
                    ssid = cookie.getValue();
                }
            }
        }

        if (account != null && ssid != null) {
            // 如果加密规则正确, 则视为已经登录.加密略
            loggin = ssid.equals(account + KEY);
        }

        System.out.println("是否匹配  :   " + loggin);
        request.getSession(true).setAttribute("loggin", loggin);

        // 跳转到登录页面
        request.getRequestDispatcher("/cookie/loginCookie.jsp").forward(request, response);
        return;
    }

}

  1. loginCookie.jsp:显示页面
<%@ page language="java" pageEncoding="UTF-8" isErrorPage="false" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<c:set var="base" value="${pageContext.request.contextPath}"/>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
    <title>
        <c:choose>
            <c:when test="${loggin==true}">欢迎您回来</c:when>
            <c:otherwise>请先登录</c:otherwise>
        </c:choose>
    </title>
</head>
<body>
<div align="center" style="margin: 10px;">
    <fieldset>
        <legend>
            当前有效的 Cookie
        </legend>
        <script>
            document.write(document.cookie);
        </script>
    </fieldset>
    <fieldset>
        <legend>
            <c:choose>
                <c:when test="${loggin ==true}">
                    欢迎您回来
                </c:when>
                <c:otherwise>
                    请先登录
                </c:otherwise>
            </c:choose>
        </legend>
        <c:choose>
            <c:when test="${loggin==true}">
                欢迎您, ${cookie.account.value }   
                <a href="${base}/loginOutCookieServlet?action=logout">注 销</a>
            </c:when>
            <c:otherwise>
                <form action="${base}/loginCookieServlet?action=login" method="post">
                    <table>
                        <tr>
                            <td>
                                帐号:
                            </td>
                            <td>
                                <input type="text" name="account" style="width: 200px;">
                            </td>
                        </tr>
                        <tr>
                            <td>
                                密码:
                            </td>
                            <td>
                                <input type="password" name="password" style="width: 200px;">
                            </td>
                        </tr>
                        <tr>
                            <td>
                                有效期:
                            </td>
                            <td>
                                <input type="radio" name="timeout" value="-1" checked>
                                关闭浏览器即失效
                                <br/>
                                <input type="radio" name="timeout"
                                       value="<%=30 * 24 * 60 * 60%>">
                                30天内有效
                                <br/>
                                <input type="radio" name="timeout"
                                       value="<%=Integer.MAX_VALUE%>">
                                永久有效
                                <br/>
                            </td>
                        </tr>
                        <tr>
                            <td>
                            </td>
                            <td>
                                <input type="submit" value=" 登  录 " class="button">
                            </td>
                        </tr>
                    </table>
                </form>
            </c:otherwise>
        </c:choose>
    </fieldset>
</div>
</body>
</html>

使用Cookie统计PV、UV量

// 客户标识  
private final String CUSTOMER_IDENTIFICATION = "CusID";  
private String uvFlag;  
  
  
/** 
 * cookie中获取用户唯一标识 采用uuid记录 存在获取不存在重新设置 
 */  
private void autoSetCookie() {  
    Cookie[] cookies = getRequest().getCookies();  
    int count = 0;  
    if (cookies != null) {  
        for (Cookie cookie : cookies) {  
            if (org.apache.commons.lang3.StringUtils.equals(  
                    cookie.getName(), CUSTOMER_IDENTIFICATION)) {  
                uvFlag = cookie.getValue();//存入数据库,以便统计  
                break;  
            }  
            count++;  
            // 该cookie在cookie列表中不存在  
            if (count == cookies.length) {  
                autoSetCid();  
            }  
        }  
    } else {  
        autoSetCid();  
    }  
}  
  
/** 
 * 自动设置客户端唯一标识 
 */  
private void autoSetCid() {  
    uvFlag = UUID.randomUUID().toString().replaceAll("[-]", "");  
    Cookie cidCookie = new Cookie(CUSTOMER_IDENTIFICATION, uvFlag);  
    cidCookie.setDomain(PropertyFileUtil.get("domain"));//写在配置文件  
    cidCookie.setMaxAge(365 * 24 * 60 * 60);  
    cidCookie.setPath("/");  
    getResponse().addCookie(cidCookie);//向客户端写Cookie  
}

参考

  1. 源码地址
  2. Servlet学习笔记(六):Cookie

Fork me on Gitee

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值