理解Cookie

1 Cookie是什么

Cookie是浏览器储存在用户电脑上的一小段文本文件。一个WEB页面或服务器,来告知浏览器按照一定规范来储存这些信息,并在随后的请求中将这些信息发送至服务器。
Cookie通常用来识别不同的用户。比如大多数需要登录的网站在用户验证成功之后都会设置一个cookie,只要这个cookie存在并可以,用户就可以自由浏览这个网站的任意页面。比如下图页面是亚马逊首页面加载时由服务端返回过来的设置的多个Cookie。


浏览器可以设置不接受Cookie,也可以设置不向服务器发送Cookie。window.navigator.cookieEnabled属性返回一个布尔值,表示浏览器是否打开Cookie功能。在浏览器向服务器发送Cookie的时候,是在一行内,将所有Cookie全部发送,多个Cookie之间用分号隔开。比如下图是亚马逊首页面加载时向服务端发送的信息:


2 Cookie属性

Cookie是有一定结构属性的,属性列表如下图:


其中Name和Value肯定是必须的,属性之间以分号隔开。

2.1 Domain属性

Domain属性指定Cookie所在的域名,比如www.greatytc.com.jianshu.com(这种写法将对所有子域名生效)、xxxsubdomain.jianshu.com
如果未指定Domain属性,则默认为,设置该Cookie的当前页面的域名。并且,比如当前访问的域名是jianshu.com,就不能将Domain设为cnblogs.com,因为Domain属性必须是当前发送Cookie的域名的一部分,只有访问的域名匹配上Domain属性,Cookie才会发送到服务端。

2.2 Path属性

Path属性用来指定Cookie路径,必须是绝对路径(比如/),如果未指定,默认为请求该Cookie的网页路径。
只有Path属性和当前向服务端发送的路径相匹配,Cookie才会发送。这里的匹配是从根路径开始逐个字符计算,只要匹配发送路径的一部分,就可以。比如,Path属性等于/a,则发送路径是/a或者/ab,Cookie都会发送。
在发送Cookie的时候,只有Domain匹配成功了,才会进行Path的匹配判断。

2.3 Expires属性

Expires属性,用于指定Cookie过期时间。它的格式采用Date.toUTCString()的格式。


如果不设置该属性,或者设为null,Cookie只在当前会话(Session)有效,浏览器窗口一旦关闭,当前Session结束,该Cookie就会被删除。如果设置了有效期,浏览器会根据本地时间,来决定Cookie是否过期。由于本地时间是不精确的,所以没有办法保证Cookie一定会在服务器指定的时间过期。
这里要多说下,根据Expires属性,可以将Cookie分为两类,Session Cookie和Permanent Cookie。
Session Cookie是最简单的Cookie,浏览器关闭之后它会被自动删除,也就是它仅在会话期间有效(和Session就扯上关系了)。

2.4 Size属性

浏览器对Cookie数量的限制,规定不一样。目前,Firefox是每个域名最多设置50个Cookie,而Safari和Chrome没有域名数量的限制。所有Cookie的累加长度限制为4KB。超过这个长度的Cookie,将被忽略,不会被设置。

2.5 HttpOnly属性

设置Cookie的时候,如果服务器加上了HttpOnly属性,则这个Cookie无法被JavaScript读取(即document.cookie不会返回这个Cookie的值),只用于向服务器发送。进行AJAX操作时,XMLHttpRequest对象也无法包括这个Cookie,主要是为了防止XSS攻击盗取Cookie。


只有在使用SLL和HTTPS协议向服务器发起请求时,才能确保Cookie被安全地发送到服务器。HttpOnly并没有提供额外的加密或者安全性上的能力,当整个机器暴露在不安全的环境时,切记绝不能通过HTTP Cookie存储、传输机密或者敏感信息。

2.6 Secure属性

Secure属性只是个标记,没有值,用来指定Cookie只能在加密协议HTTPS下发送到服务器。该属性只是一个开关,不需要指定值。如果通信是HTTPS协议,该开关自动打开,在http模式中不会向服务回发Cookie的验证信息。

以上属性可以同时设置一个或多个,也没有次序的要求。如果服务器想改变一个早先设置的Cookie,必须同时满足四个条件:Cookie的key、domain、path和secure都匹配。只要有一个属性不同,就会生成一个全新的Cookie,而不是替换掉原来那个Cookie

3 Cookie操作

3.1服务端Java操作

根据名字获取Cookie:

   /**
     * 根据Cookie名称得到Cookie对象,不存在该对象则返回null
     *
     * @param request
     * @param name
     * @return
     */
    public static Cookie getCookie(HttpServletRequest request, String name) {
        Cookie[] cookies = request.getCookies();
 
        if ((null == cookies) || (null == name) || (name.length() == 0)) {
            return null;
        }
        Cookie cookie = null;
 
        for (Cookie c : cookies) {
            if (name.equals(c.getName())) {
                cookie = c;
                break;
            }
        }
        return cookie;
    }

设置一个Cookie:

   /**
     * 设置一条新的Cookie,可以指定过期时间(单位:秒)
     *
     * @param response
     * @param name
     * @param value
     * @param maxValue
     */
    public static void setCookie(HttpServletResponse response, String name,
            String value, int maxValue) {
        if (null == name) {
            return;
        }
 
        if (null == value) {
            value = "";
        }
 
        Cookie cookie;
        try {
            cookie = new Cookie(name, URLEncoder.encode(value, "UTF-8"));
            cookie.setPath(path);
            if(domain != null) {
                cookie.setDomain(domain);
            }
            if (maxValue != 0) {
                cookie.setMaxAge(maxValue);
            } else {
                cookie.setMaxAge(cookieMaxAge);
            }
 
            response.addCookie(cookie);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }

删除一条Cookie:

   /**
     * 移出指定名称的cookie,设定expires为0即可
     * @param request
     * @param response
     * @param name
     */
    public static void removeCookie(HttpServletRequest request,
            HttpServletResponse response, String name) {
        if (null == name) {
            return;
        }
 
        Cookie cookie = getCookie(request, name);
 
        if (null != cookie) {
            cookie.setPath(path);
            if(domain != null) {
                cookie.setDomain(domain);
            }
            cookie.setValue("");
            cookie.setMaxAge(0);
            response.addCookie(cookie);
        }
    }

3.2前端JS操作

设置Cookie:

/*
 *  设置 cookie
 *  @param {String} name cookie名称
 *  @param {String} value cookie值
 *  @param {Object} option 附加参数
 *  @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'alipay.com', secure: true });
 */
function setCookie(name,value,options) {
    options = options || {};

    if (value === null) {   //设置 value 为 null,则清除名称为 name 的 cookie
        value = '';
        options = $.extend({}, options);
        options.expires = -1;
    }

    var expires = '';
    if (options.expires && typeof options.expires == 'number') {
        var date = new Date();
        //计算过期时间:当前的时间 + 传入的过期天数
        date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));  //setTime() : 以毫秒设置 Date 对象
        expires = '; expires=' + date.toUTCString();
    }

    var path = options.path ? '; path=' + (options.path) : '';
    var domain = options.domain ? '; domain=' + (options.domain) : '';
    var secure = options.secure ? '; secure' : '';

    document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
}

获取Cookie:

/*
 *  获取 cookie
 *  @param {String} name cookie名称
 */
function getCookie(name){
    var cookieValue = null;
    if(document.cookie && document.cookie !== ''){
        var cookies = document.cookie.split(';');
        for(var i=0; i<cookies.length; i++){
            var cookie = cookies[i].replace(/(^\s*|\s*$)/g,''); //去除空格
            if(cookie.substring(0, name.length + 1) === (name + '=') ){
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,951评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,606评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,601评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,478评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,565评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,587评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,590评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,337评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,785评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,096评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,273评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,935评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,578评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,199评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,440评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,163评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,133评论 2 352

推荐阅读更多精彩内容