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;
}