Cookie的诞生

由于HTTP协议是无状态的,而服务器端的业务必须是要有状态的。Cookie诞生的最初目的是为了存储web中的状态信息,以方便服务器端使用。比如判断用户是否是第一次访问网站。目前最新的规范是RFC 6265,它是一个由浏览器服务器共同协作实现的规范。

Cookie的处理分为:

  • 服务器像客户端发送cookie
  • 浏览器将cookie保存
  • 之后每次http请求浏览器都会将cookie发送给服务器端

服务器端的发送与解析

发送cookie

服务器端像客户端发送Cookie是通过HTTP响应报文实现的,在Set-Cookie中设置需要像客户端发送的cookie,cookie格式如下:

Set-Cookie: "name=value;domain=.domain.com;path=/;expires=Sat, 11 Jun 2016 11:29:42 GMT;HttpOnly;secure"

其中name=value是必选项,其它都是可选项。Cookie的主要构成如下:

  • name:一个唯一确定的cookie名称。通常来讲cookie的名称是不区分大小写的。
  • value:存储在cookie中的字符串值。最好为cookie的name和value进行url编码
  • domain:cookie对于哪个域是有效的。所有向该域发送的请求中都会包含这个cookie信息。这个值可以包含子域(如:yq.aliyun.com),也可以不包含它(如:.aliyun.com,则对于aliyun.com的所有子域都有效).
  • path: 表示这个cookie影响到的路径,浏览器跟会根据这项配置,像指定域中匹配的路径发送cookie。
  • expires:失效时间,表示cookie何时应该被删除的时间戳(也就是,何时应该停止向服务器发送这个cookie)。如果不设置这个时间戳,浏览器会在页面关闭时即将删除所有cookie;不过也可以自己设置删除时间。这个值是GMT时间格式,如果客户端和服务器端时间不一致,使用expires就会存在偏差
  • max-age: 与expires作用相同,用来告诉浏览器此cookie多久过期(单位是秒),而不是一个固定的时间点。正常情况下,max-age的优先级高于expires。
  • HttpOnly: 告知浏览器不允许通过脚本document.cookie去更改这个值,同样这个值在document.cookie中也不可见。但在http请求张仍然会携带这个cookie。注意这个值虽然在脚本中不可获取,但仍然在浏览器安装目录中以文件形式存在。这项设置通常在服务器端设置。
  • secure: 安全标志,指定后,只有在使用SSL链接时候才能发送到服务器,如果是http链接则不会传递该信息。就算设置了secure 属性也并不代表他人不能看到你机器本地保存的 cookie 信息,所以不要把重要信息放cookie就对了

    服务器端设置cookie示例如下:
var http = require('http');
var fs = require('fs'); http.createServer(function(req, res) {
res.setHeader('status', '200 OK');
res.setHeader('Set-Cookie', 'isVisit=true;domain=.yourdomain.com;path=/;max-age=1000');
res.write('Hello World');
res.end();
}).listen(8888); console.log('running localhost:8888')





直接设置Set-Cookie过于原始,我们可以对cookie的设置过程做如下封装:

var serilize = function(name, val, options) {
if (!name) {
throw new Error("coolie must have name");
}
var enc = encodeURIComponent;
var parts = []; val = (val !== null && val !== undefined) ? val.toString() : "";
options = options || {};
parts.push(enc(name) + "=" + enc(val));
// domain中必须包含两个点号
if (options.domain) {
parts.push("domain=" + options.domain);
}
if (options.path) {
parts.push("path=" + options.path);
}
// 如果不设置expires和max-age浏览器会在页面关闭时清空cookie
if (options.expires) {
parts.push("expires=" + options.expires.toGMTString());
}
if (options.maxAge && typeof options.maxAge === "number") {
parts.push("max-age=" + options.maxAge);
}
if (options.httpOnly) {
parts.push("HTTPOnly");
}
if (options.secure) {
parts.push("secure");
} return parts.join(";");
}

需要注意的是,如果给cookie设置一个过去的时间,浏览器会立即删除该cookie;此外domain项必须有两个点,因此不能设置为localhost:

something that wasn't made clear to me here and totally confused me for a while was that domain names must contain at least two dots (.),hence 'localhost' is invalid and the browser will refuse to set the cookie!

服务器端解析cookie

cookie可以设置不同的域与路径,所以对于同一个name value,在不同域不同路径下是可以重复的,浏览器会按照与当前请求url或页面地址最佳匹配的顺序来排定先后顺序



所以当前端传递到服务器端的cookie有多个重复name value时,我们只需要最匹配的那个,也就是第一个。服务器端解析代码如下:

var parse = function(cstr) {
if (!cstr) {
return null;
} var dec = decodeURIComponent;
var cookies = {};
var parts = cstr.split(/\s*;\s*/g);
parts.forEach(function(p){
var pos = p.indexOf('=');
// name 与value存入cookie之前,必须经过编码
var name = pos > -1 ? dec(p.substr(0, pos)) : p;
var val = pos > -1 ? dec(p.substr(pos + 1)) : null;
//只需要拿到最匹配的那个
if (!cookies.hasOwnProperty(name)) {
cookies[name] = val;
}/* else if (!cookies[name] instanceof Array) {
cookies[name] = [cookies[name]].push(val);
} else {
cookies[name].push(val);
}*/
}); return cookies;
}

客户端的存取

浏览器将后台传递过来的cookie进行管理,并且允许开发者在JavaScript中使用document.cookie来存取cookie。但是这个接口使用起来非常蹩脚。它会因为使用它的方式不同而表现出不同的行为

  • 当用来获取属性值时,document.cookie返回当前页面可用的(根据cookie的域、路径、失效时间和安全设置)所有的字符串,字符串的格式如下:
"name1=value1;name2=value2;name3=value3";
  • 当用来设置值的时候,document.cookie属性可设置为一个新的cookie字符串。这个字符串会被解释并添加到现有的cookie集合中。如:
document.cookie = "_fa=aaaffffasdsf;domain=.dojotoolkit.org;path=/"

设置document.cookie并不会覆盖cookie,除非设置的name value domain path都与一个已存在cookie重复。

由于cookie的读写非常不方便,我们可以自己封装一些函数来处理cookie,主要是针对cookie的添加、修改、删除。

var cookieUtils = {
get: function(name){
var cookieName=encodeURIComponent(name) + "=";
//只取得最匹配的name,value
var cookieStart = document.cookie.indexOf(cookieName);
var cookieValue = null; if (cookieStart > -1) {
// 从cookieStart算起
var cookieEnd = document.cookie.indexOf(';', cookieStart);
//从=后面开始
if (cookieEnd > -1) {
cookieValue = decodeURIComponent(document.cookie.substring(cookieStart + cookieName.length, cookieEnd));
} else {
cookieValue = decodeURIComponent(document.cookie.substring(cookieStart + cookieName.length, document.cookie.length));
}
} return cookieValue;
}, set: function(name, val, options) {
if (!name) {
throw new Error("coolie must have name");
}
var enc = encodeURIComponent;
var parts = []; val = (val !== null && val !== undefined) ? val.toString() : "";
options = options || {};
parts.push(enc(name) + "=" + enc(val));
// domain中必须包含两个点号
if (options.domain) {
parts.push("domain=" + options.domain);
}
if (options.path) {
parts.push("path=" + options.path);
}
// 如果不设置expires和max-age浏览器会在页面关闭时清空cookie
if (options.expires) {
parts.push("expires=" + options.expires.toGMTString());
}
if (options.maxAge && typeof options.maxAge === "number") {
parts.push("max-age=" + options.maxAge);
}
if (options.httpOnly) {
parts.push("HTTPOnly");
}
if (options.secure) {
parts.push("secure");
} document.cookie = parts.join(";");
},
delete: function(name, options) {
options.expires = new Date(0);// 设置为过去日期
this.set(name, null, options);
}
}

好好了解一下Cookie的更多相关文章

  1. 再好好聊聊 HTTP 里的 Cookie | 实用 HTTP

    题图:by Juan Pablo Arenas 一.序 Hi,大家好,我是承香墨影! HTTP 协议在网络知识中占据了重要的地位,HTTP 协议最基础的就是请求和响应的报文,而报文又是由报文头(Hea ...

  2. IE10、IE11 User-Agent 导致的 ASP.Net 网站无法写入Cookie 问题

    你是否遇到过当使用一个涉及到Cookie操作的网站或者管理系统时,IE 6.7.8.9下都跑的好好的,唯独到了IE10.11这些高版本浏览器就不行了?好吧,这个问题码农连续2天内遇到了2次.那么,我们 ...

  3. 登陆后设置cookie的方法

    public void SetCookie(string userName, string role,string cookieValueName) {FormsAuthentication.Form ...

  4. IE10、IE11 User-Agent 网站无法写入Cookie 问题[转]

    你是否遇到过当使用一个涉及到Cookie操作的网站或者管理系统时,IE 6.7.8.9下都跑的好好的,唯独到了IE10.11这些高版本浏览器就不行了?好吧,这个问题码农连续2天内遇到了2次.那么,我们 ...

  5. php/js互传cookie中文乱码的问题

    问题发现: 过去好好的,今天突然网页出现了问题. 在猎豹和IE都出现问题,在360浏览器就正常. 经过排错,最终发现:  js存储cookie,php读取的时候成了乱码 . 问题分析: 这是因为文字编 ...

  6. IE10、IE11 无法写入Cookie

    IE10.IE11 User-Agent 导致的 ASP.Net 网站无法写入Cookie 问题 你是否遇到过当使用一个涉及到Cookie操作的网站或者管理系统时,IE 6.7.8.9下都跑的好好的, ...

  7. Session和Cookie的分析与区别

    首先说一下Web.config文件中的cookieless="false"的理解 cookieless="false"表示: 如果用户浏览器支持cookie时启 ...

  8. 会话控制:cookie和session基础学习笔记

    在多次HTTP连接间维护用户与同一用户发出的不同请求之间关联的情况称为维护一个会话(session) 我们可以简单理解为浏览器的开关. 其实对cookie和session也是主要为curd操作 coo ...

  9. ASP.NET 之深入浅出Session和Cookie

    在做人事档案管理系统中,对于Session和Cookie的使用后理解更加深刻了,下面对本知识点总结学习. Session是什么? 简单来说就是服务器给客户端的一个编号.当一台WWW服务器运行时,可能有 ...

随机推荐

  1. CORS详解[译]

    介绍 由于同源策略的缘故,以往我们跨域请求,会使用诸如JSON-P(不安全)或者代理(设置代理和维护繁琐)的方式.而跨源资源共享(Cross-Origin Resource Sharing)是一个W3 ...

  2. [高并发]Java高并发编程系列开山篇--线程实现

    Java是最早开始有并发的语言之一,再过去传统多任务的模式下,人们发现很难解决一些更为复杂的问题,这个时候我们就有了并发. 引用 多线程比多任务更加有挑战.多线程是在同一个程序内部并行执行,因此会对相 ...

  3. 重撸js_2_基础dom操作

    1.node 方法 返回 含义 nodeName String 获取节点名称 nodeType Number 获取节点类型 nodeValue String 节点的值(注意:文本也是节点) 2.inn ...

  4. ASP.NET MVC5+EF6+EasyUI 后台管理系统(1)-前言与目录(持续更新中...)

    开发工具:VS2015(2012以上)+SQL2008R2以上数据库  您可以有偿获取一份最新源码联系QQ:729994997 价格 666RMB  升级后界面效果如下: 任务调度系统界面 http: ...

  5. ASP.NET Core的路由[4]:来认识一下实现路由的RouterMiddleware中间件

    虽然ASP.NET Core应用的路由是通过RouterMiddleware这个中间件来完成的,但是具体的路由解析功能都落在指定的Router对象上,不过我们依然有必要以代码实现的角度来介绍一下这个中 ...

  6. C++随笔:.NET CoreCLR之GC探索(4)

    今天继续来 带大家讲解CoreCLR之GC,首先我们继续看这个GCSample,这篇文章是上一篇文章的继续,如果有不清楚的,还请翻到我写的上一篇随笔.下面我们继续: // Initialize fre ...

  7. C# await和async

    基础阅读:http://www.cnblogs.com/jesse2013/p/async-and-await.html 答疑阅读:http://www.cnblogs.com/heyuquan/ar ...

  8. Autofac - 属性注入

    属性注入不同于通过构造函数方式传入参数. 这里是通过注入的方式, 在类创建完毕之后, 资源释放之前, 给属性赋值. 这里, 我重新弄一些类来演示这一篇吧. public class ClassA { ...

  9. javascript函数

    array.sort(function(a, b){ return a -b ; } )   把数组 array 按照从小到大排序. [11, 22, 586, 10, -58, 86].sort(f ...

  10. 纸箱堆叠 bzoj 2253

    纸箱堆叠 (1s 128MB) box [问题描述] P 工厂是一个生产纸箱的工厂.纸箱生产线在人工输入三个参数 n, p, a 之后,即可自动化生产三边边长为 (a mod P, a^2 mod p ...