在刚学web的时候就了解了cookie,只是并没有在项目中用到过,对它的一些细节也没有仔细了解过,最近重构一个单点登录的项目,其中用到了cookie,现对一些自己之前没有注意的点进行总结下。
cookie的属性选项
cookie
选项包括:expires
、domain
、path
、secure
、HttpOnly
。在设置任一个cookie
时都可以设置相关的这些属性,当然也可以不设置,这时会使用这些属性的默认值。
expires(max-age)
expires
选项用来设置cookie
失效日期。对于失效的cookie
浏览器会清空。如果没有设置该选项,则默认有效期为session
,即会话cookie
。这种cookie
在浏览器关闭后就没有了。
expires 是 http/1.0协议中的选项,在新的http/1.1协议中expires已经由 max-age 选项代替,两者的作用都是限制cookie的有效时间。expires的值是一个时间点(cookie失效时刻= expires),而max-age 的值是一个以秒为单位时间段(cookie失效时刻= 创建时刻+ max-age)。另外,max-age 的默认值是 -1(即有效期为 session );若max-age有三种可能值:负数、0、正数。负数:有效期session;0:删除cookie;正数:有效期为创建时刻+ max-age
domain和path
domain
是域名,path
是路径,domain
和path
一起来限制 cookie 能被哪些 URL 访问。
一句话概括:某cookie的 domain
为“baidu.com”, path
为“/ ”,若请求的URL(URL 可以是js/html/img/css资源请求,但不包括 XHR 请求)的域名是“baidu.com”或其子域如“api.baidu.com”、“dev.api.baidu.com”,且 URL 的路径是“/ ”或子路径“/home”、“/home/login”,则浏览器会将此 cookie 添加到该请求的 cookie 头部中。
所以domain
和path
2个选项共同决定了cookie
何时被浏览器自动添加到请求头部中发送出去。如果没有设置这两个选项,则会使用默认值。domain
的默认值为设置该cookie
的网页所在的域名,path
默认值为设置该cookie
的网页所在的目录。
domain是可以设置为页面本身的域名(本域),或页面本身域名的父域,但不能是公共后缀 public suffix。举例说明下:如果页面域名为 www.baidu.com, domain可以设置为“www.baidu.com”,也可以设置为“baidu.com”,但不能设置为“.com”或“com”。
关于细节,接下来会有讨论。
secure
secure
选项用来设置cookie
只在确保安全的请求中才会发送。当请求是HTTPS
或者其他安全协议时,包含secure
选项的cookie
才能被发送至服务器。
默认情况下,cookie
不会带secure
选项(即为空)。所以默认情况下,不管是HTTPS
协议还是HTTP
协议的请求,cookie
都会被发送至服务端。但要注意一点,secure
选项只是限定了在安全情况下才可以传输给服务端,但并不代表你不能看到这个 cookie。
httpOnly
这个选项用来设置cookie
是否能通过 js
去访问。默认情况下,cookie
不会带httpOnly
选项(即为空),所以默认情况下,客户端是可以通过js
代码去访问(包括读取、修改、删除等)这个cookie
的。当cookie
带httpOnly
选项时,客户端则无法通过js
代码去访问(包括读取、修改、删除等)这个cookie
。
在客户端是不能通过js
代码去设置一个httpOnly
类型的cookie
的,这种类型的cookie
只能通过服务端来设置。
cookie域的详细讨论
现在有如下3个域名,一个顶级域名、一个二级域名和一个三级域名:
① zydya.com
②blog.zyday.com
③one.blog.zyday.com
- 首先在①zyday.com域名下设置cookie,做四次测试,分别设置domain参数为空、'zyday.com'、'blog.zyday.com'与'one.blog.zyday.com'。
√表示该域名下能取到cookie,×表示不能取到cookie
domain参数 | zydya.com | blog.zyday.com | one.blog.zyday.com | |
setcookie('name',1,time()+1) | √ | √ | √ | |
setcookie('name',1,time()+1,'/','zyday.com') | √ | √ | √ | |
setcookie('name',1,time()+1,'/','blog.zyday.com') | × | × | × | |
setcookie('name',1,time()+1,'/','one.blog.zyday.com') | × | × | × |
- 然后在②blog.zyday.com域名下设置cookie,测试条件同上
domain参数 | zydya.com | blog.zyday.com | one.blog.zyday.com |
setcookie('name',1,time()+1) | × | √ | √ |
setcookie('name',1,time()+1,'/','zyday.com') | √ | √ | √ |
setcookie('name',1,time()+1,'/','blog.zyday.com') | × | √ | √ |
setcookie('name',1,time()+1,'/',one.blog.zyday.com') | × | × | × |
看第二行,domain参数是zyday.com,是blog.zyday.com的父域名,那么zyday.com下所有子域名(包括zyday.com、blog.zyday.com、one.blog.zyday.com)都能接收到cookie。
当domain为自身域名时,那么其父域名受影响,其本身与其子域名可以接收到cookie。而设置其子域名或其他域名时,所有域名都接收不到cookie了。
- 最后在③one.blog.zyday.com域名下设置cookie
domain参数 | zydya.com | blog.zyday.com | one.blog.zyday.com |
setcookie('name',1,time()+1) | × | × | √ |
setcookie('name',1,time()+1,'/','zyday.com') | √ | √ | √ |
setcookie('name',1,time()+1,'/','blog.zyday.com') | × | √ | √ |
setcookie('name',1,time()+1,'/',one.blog.zyday.com') | × | × | √ |
总结:
1.在setcookie中省略domain参数,那么domain默认为当前域名。
2.domain参数可以设置父域名以及自身,但不能设置其它域名,包括子域名,否则cookie不起作用。
那么cookie的作用域:domain本身以及domain下的所有子域名。
跨域cookie的一种实现方式
在开发中我们会遇到cookie跨域访问的问题,比如单点登录。下面是一种解决方案。
现在有两个域名a.com和b.com,需要在a.com中设置cookie,并且在b.com中可以访问到。常规的做法是不行的。
1.在a.com中的页面中添加一个iframe,iframe的src指向b.com的一个请求,假如叫做b.com/setCookie.jsp。当然你也可以通过这个请求传递参数,在b.com/setCookie.jsp中接受做处理。
2.在b.com/setCookie.jsp中设置cookie。当然还需要借助p3p协议:
asp.net设置p3p的方法:
HttpContext.Current.Response.AddHeader("p3p", "CP=\""IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT\""")
PHP设置p3p的方法:
header('P3P:CP="IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT"');
JSP设置p3p的方法:
response.setHeader("P3P","CP='IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT'")
参考链接:
https://segmentfault.com/a/1190000004556040
http://blog.csdn.net/czhphp/article/details/65628977
http://www.cnblogs.com/waters/articles/2869855.html
http://www.cnblogs.com/meteoric_cry/archive/2011/10/24/2223086.html