Cookie的操作

什么是cookie

cookie的由来

在客户端和服务端通信的过程中,服务端如果需要记录客户端的信息,就要设计一类文件来实现存储。服务端存储用户信息的东西就是session,用户在某个站点留下的信息可以存储在服务器中。但是单单只用session还不够,因为这样会服务器需要存储大量的用户信息,压力会很大,所以cookie就应运而生了。
cookie和session经常在网上被大家放在一起讨论,原因在于它和session的目的都是存储记录用户的信息的,但是除此之外,二者在其他方面是几乎完全不一样的。至于二者的机制有何区别,可以参考这篇博文:Cookie 与 Session 的区别

简要概括一下session和cookie的区别:
cookie存储在客户端,session存储在服务端;
cookie可以用来跟踪会话,也可以保存用户名和密码;session用来跟踪会话

cookie的基本属性

在控制台中,我们可以在application选项中查看到网站的cookie,cookie的属性也显示在其中,包括了 Name、value、Domain、path、Expires/Max-Age、Size、HTTP、Secure等等

  • Name: cookie名称,创建后无法改动
  • value:cookie值,若为Unicode字符,则需要字符编码;若为二进制数据,则需要base64编码
  • domain:可以访问该cookie的域名。非顶级域名cookie的domain只能是顶级域名或者自身域名,且无法读取其他非顶级域名的cookie(?),顶级域名cookie的domain只能是顶级域名
  • path:可以访问该cookie的路径
  • expires/max-age:保持有效的时间,单位为秒,若为负数,关闭浏览器即消失。expires已经过时,尽管今天的浏览器仍然支持它。请改用max-age变量,因为它更容易使用。注意不要使用“expires”作为变量名来存储数据。
  • http:httponly,若为true,则只有在http请求头中会带有该cookie的信息,无法通过document.cookie访问
  • secure:是否用https传递cookie

一般的,一个浏览器针对一个网站最多存20个cookie,浏览器总共只允许存放300个cookie。每个cookie的长度不能超过4K。
cookie是以键值对形式保存的,各个cookie之间一般以分号隔开,比如这样:

theme=blue; max-age=60; path=/; domain=baidu.com

补充:如果没有设置有效时间,那么cookie是保存在计算机内存的,浏览器关闭即删;若设置了有效时间,那么就会保存到硬盘

关于安全性

常见的攻击方式

防范

用户可以设置HttpOnly和secure属性来抵御攻击。设置了HttpOnly属性后,就可以防御脚本读取cookie信息(XSS); 设置了secure=true,cookie只能在https连接中被浏览器传递到服务端
cookie加密也是一个基本操作
cookie安全的话题可以参考:单点登录与权限管理本质:cookie安全问题

cookie的具体操作

网上看到的一个简易封装的代码

var cookieUtil = {

    setCookie: function(name, value, expiresDays) {
        var date = new Date();
        date.setDate(date.getDate() + expiresDays);
        document.cookie = name + "=" + escape(value) + ";" + ((expiresDays == null) ? "" : ";expires=" + date.toGMTString());
    },

    getCookie: function(name) {
        var cookies = document.cookie;
        var start = cookies.indexOf(name + "=");

        if (start === -1) {
            return "";
        }

        start = start + name.length + 1;
        var end = cookies.indexOf(";", start);

        //是最后一个键值对(末尾没有分号)
        if (end === -1) {
            end = document.cookie.length;
        }

        return unescape(document.cookie.substring(start, end));

    },

    deleteCookie: function(name) {
        //将过期日期设置为前一天
        this.setCookie(name, "", -1);
    }
}

设置cookie

设置cookie比较简单,只需将cookie所需的字符串分配给document.cookie属性即可。

document.cookie = "theme=" + encodeURIComponent("blue theme") + "; max-age=" + 60*60*24 + "; path=/; domain=baidu.com";

封装成一个函数:

function setCookie(cookieName, cookieValue, days, domain) {
    var domainString = domain ? ("; domain=" + domain) : '';
    document.cookie = cookieName + "=" + encodeURIComponent(cookieValue) + "; max-age=" + 60*60*24*days + "; path=/" + domainString;
}

//调用
setCookie("colortheme", "theme", 2, "baidu.com")

或者

//from : https://www.sitepoint.com/how-to-deal-with-cookies-in-javascript/
function createCookie(name, value, expires, path, domain) {
  var cookie = name + "=" + escape(value) + ";";

  if (expires) {
    // If it's a date
    if(expires instanceof Date) {
      // If it isn't a valid date
      if (isNaN(expires.getTime()))
       expires = new Date();
    }
    else
      expires = new Date(new Date().getTime() + parseInt(expires) * 1000 * 60 * 60 * 24);

    cookie += "expires=" + expires.toGMTString() + ";";
  }

  if (path)
    cookie += "path=" + path + ";";
  if (domain)
    cookie += "domain=" + domain + ";";

  document.cookie = cookie;
}

// Usage
createCookie("website", "audero.it", new Date(new Date().getTime() + 10000));
createCookie("author", "aurelio", 30);

读取cookie


// 1
function getCookie(cookieName) {
    var cookieName = encodeURIComponent(cookieName) + "=",
        cookieStart = document.cookie.indexOf(cookieName),
        cookieValue = null;
    if (cookieStart > 1) {
        var cookieEnd = document.cookie.indexOf(";", cookieStart);
        if (cookieEnd === -1) {
            cookieEnd = document.cookie.length;
        }
        cookieValue = decodeURIComponent(document.cookir.substring(cookieStart + document.cookie.length, cookieEnd))
    }
    return cookieValue;
}

// 2
function getCookie(cookieName) {
    var cookieString = document.cookie;
    if (cookieString.length !== 0) {
        var cookieArray = cookieString.split('; ');
        for (var i = 0; i < cookieArray.length; i++) {
            var cookieValue = cookieArray[i].match(cookieName + '=(.*)');
            if (cookieValue) {
                return decodeURIComponent(cookieValue[1]);
            }
        }
    }
    return '';
}

删除cookie

有时您可能想要删除Cookie,例如访问者退出您的网站时。为此,可以将max-age变量设置为相同路径和域中相同cookie的0(零)或者是负数:

function deleteCookie(cookieName, domain) {
    var domainString = domain ? ("; domain=" + domain) : '';
    document.cookie = cookieName + "=; max-age=0; path=/" + domainString;
}

修改cookie

可以新建一个同名的cookie覆盖原有的cookie

扩展

cookie操作的第三方库:
js-cookie
cookie-encryption



参考:
How to Use Cookies in JavaScript

掘进 - cookie 小结

详解 Cookie 纪要