Cookie的介绍及使用
咱们不搞一开始就一大堆理论知识介绍,怕把人讲懵了...... 咱们换一个思维方式——"从现象看本质",先说说我们看到了什么,再从看到的现象中提出问题,最后深入寻找答案。
我们看到的 cookie
我自己创建了一个网站,网址为http://ppsc.sankuai.com。在这个网页中我设置了几个cookie:JSSESSIONID,PA_VTIME,skmtutc,test。
在 chrome 浏览器中打开这个网站,进入开发者模式,点击Resources栏 -> 选择cookies,我们会看到如下图所示的界面:
解释一下:左边栏Cookies下方会列举当前网页中设置过cookie的域都有哪些。上图中只有一个域,即“ppsc.sankuai.com”。而右侧区域显示的就是某个域下具体的 cookie 列表,对应上图就是“ppsc.sankuai.com”域下设置的4个cookie。
在这个网页中我往http://ppsc.sankuai.com/getList接口发了一个 Ajax 请求,request header如下图所示:
从上图中我们会看到request header中自动添加了Cookie字段(我并没有手动添加这个字段哦~),Cookie字段的值其实就是我设置的那4个 cookie。这个请求最终会发送到http://ppsc.sankuai.com这个服务器上,这个服务器就能从接收到的request header中提取那4个cookie。
上面两张图展示了cookie的基本通信流程:设置cookie => cookie被自动添加到request header中 => 服务端接收到cookie。这个流程中有几个问题需要好好研究:
什么样的数据适合放在
cookie中?cookie是怎么设置的?cookie为什么会自动加到request header中?cookie怎么增删查改?
我们要带着这几个问题继续往下阅读。
cookie 是怎么工作的?
首先必须明确一点,存储cookie是浏览器提供的功能。cookie 其实是存储在浏览器中的纯文本,浏览器的安装目录下会专门有一个 cookie 文件夹来存放各个域下设置的cookie。
当网页要发http请求时,浏览器会先检查是否有相应的cookie,有则自动添加在request header中的cookie字段中。这些是浏览器自动帮我们做的,而且每一次http请求浏览器都会自动帮我们做。这个特点很重要,因为这关系到“什么样的数据适合存储在cookie中”。
存储在cookie中的数据,每次都会被浏览器自动放在http请求中,如果这些数据并不是每个请求都需要发给服务端的数据,浏览器这设置自动处理无疑增加了网络开销;但如果这些数据是每个请求都需要发给服务端的数据(比如身份认证信息),浏览器这设置自动处理就大大免去了重复添加操作。所以对于那设置“每次请求都要携带的信息(最典型的就是身份认证信息)”就特别适合放在cookie中,其他类型的数据就不适合了。
但在 localStorage 出现之前,cookie被滥用当做了存储工具。什么数据都放在cookie中,即使这些数据只在页面中使用而不需要随请求传送到服务端。当然cookie标准还是做了一些限制的:每个域名下的cookie 的大小最大为4KB,每个域名下的cookie数量最多为20个(但很多浏览器厂商在具体实现时支持大于20个)。
cookie 的格式
document.cookie
JS 原生的 API提供了获取cookie的方法:document.cookie(注意,这个方法只能获取非 HttpOnly 类型的cookie)。在 console 中执行这段代码可以看到结果如下图:
打印出的结果是一个字符串类型,因为cookie本身就是存储在浏览器中的字符串。但这个字符串是有格式的,由键值对 key=value构成,键值对之间由一个分号和一个空格隔开。
cookie 的属性选项
每个cookie都有一定的属性,如什么时候失效,要发送到哪个域名,哪个路径等等。这些属性是通过cookie选项来设置的,cookie选项包括:expires、domain、path、secure、HttpOnly。在设置任一个cookie时都可以设置相关的这些属性,当然也可以不设置,这时会使用这些属性的默认值。在设置这些属性时,属性之间由一个分号和一个空格隔开。代码示例如下:
"key=name; expires=Thu, 25 Feb 2016 04:18:00 GMT; domain=ppsc.sankuai.com; path=/; secure; HttpOnly"
expires
expires选项用来设置“cookie 什么时间内有效”。expires其实是cookie失效日期,expires必须是 GMT 格式的时间(可以通过new Date().toGMTString()或者 new Date().toUTCString() 来获得)。
如expires=Thu, 25 Feb 2016 04:18:00 GMT表示cookie讲在2016年2月25日4:18分之后失效,对于失效的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是路径,两者加起来就构成了 URL,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和path2个选项共同决定了cookie何时被浏览器自动添加到请求头部中发送出去。如果没有设置这两个选项,则会使用默认值。domain的默认值为设置该cookie的网页所在的域名,path默认值为设置该cookie的网页所在的目录。
特别说明1:
发生跨域xhr请求时,即使请求URL的域名和路径都满足 cookie 的 domain 和 path,默认情况下cookie也不会自动被添加到请求头部中。若想知道原因请阅读本文最后一节)特别说明2:
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。
下面我们设置一个 secure类型的 cookie:
document.cookie = "name=huang; secure";
之后你就能在控制台中看到这个 cookie 了,如下图所示:
这里有个坑需要注意下:
如果想在客户端即网页中通过 js 去设置secure类型的 cookie,必须保证网页是https协议的。在http协议的网页中是无法设置secure类型cookie的。
httpOnly
这个选项用来设置cookie是否能通过 js 去访问。默认情况下,cookie不会带httpOnly选项(即为空),所以默认情况下,客户端是可以通过js代码去访问(包括读取、修改、删除等)这个cookie的。当cookie带httpOnly选项时,客户端则无法通过js代码去访问(包括读取、修改、删除等)这个cookie。
在客户端是不能通过js代码去设置一个httpOnly类型的cookie的,这种类型的cookie只能通过服务端来设置。
那我们在页面中怎么知道哪些cookie是httpOnly类型的呢?看下图:
凡是httpOnly类型的cookie,其 HTTP 一列都会打上√,如上图中的PA_VTIME。你通过document.cookie是不能获取的,也不能修改PA_VTIME的。
——
httpOnly与安全从上面介绍中,大家是否会有这样的疑问:为什么我们要限制客户端去访问
cookie?其实这样做是为了保障安全。试想:如果任何 cookie 都能被客户端通过
document.cookie获取会发生什么可怕的事情。当我们的网页遭受了 XSS 攻击,有一段恶意的script脚本插到了网页中。这段script脚本做的事情是:通过document.cookie读取了用户身份验证相关的 cookie,并将这些 cookie 发送到了攻击者的服务器。攻击者轻而易举就拿到了用户身份验证信息,于是就可以摇摇大摆地冒充此用户访问你的服务器了(因为攻击者有合法的用户身份验证信息,所以会通过你服务器的验证)。
如何设置 cookie?
知道了cookie的格式,cookie的属性选项,接下来我们就可以设置cookie了。首先得明确一点:cookie既可以由服务端来设置,也可以由客户端来设置。
服务端设置 cookie
不管你是请求一个资源文件(如 html/js/css/图片),还是发送一个ajax请求,服务端都会返回response。而response header中有一项叫set-cookie,是服务端专门用来设置cookie的。如下图所示,服务端返回的response header中有5个set-cookie字段,每个字段对应一个cookie(注意不能将多个cookie放在一个set-cookie字段中),set-cookie字段的值就是普通的字符串,每个cookie还设置了相关属性选项。
注意:
一个
set-Cookie字段只能设置一个cookie,当你要想设置多个 cookie,需要添加同样多的set-Cookie字段。服务端可以设置cookie 的所有选项:
expires、domain、path、secure、HttpOnly
客户端设置 cookie
在网页即客户端中我们也可以通过js代码来设置cookie。如我当前打开的网址为http://dxw.st.sankuai.com/mp/,在控制台中我们执行了下面代码:
document.cookie = "name=Jonh; ";
查看浏览器 cookie 面板如下图所示,cookie确实设置成功了,而且属性选项 domain、path、expires都用了默认值。
再执行下面代码:
document.cookie="age=12; expires=Thu, 26 Feb 2116 11:50:25 GMT; domain=sankuai.com; path=/";
查看浏览器cookie 面板,如下图所示,新的cookie设置成功了,而且属性选项 domain、path、expires都变成了设定的值。
注意:
客户端可以设置cookie 的下列选项:
expires、domain、path、secure(有条件:只有在https协议的网页中,客户端设置secure类型的 cookie 才能成功),但无法设置HttpOnly选项。
用 js 如何设置多个 cookie
当要设置多个cookie时, js 代码很自然地我们会这么写:
document.cookie = "name=Jonh; age=12; class="111"";
但你会发现这样写只是添加了第一个cookie“name=John”,后面的所有cookie都没有添加成功。所以最简单的设置多个cookie的方法就在重复执行document.cookie = "key=name",如下:
document.cookie = "name=Jonh";
document.cookie = "age=12";
document.cookie = "class=111";
如何修改、删除
修改 cookie
要想修改一个cookie,只需要重新赋值就行,旧的值会被新的值覆盖。但要注意一点,在设置新cookie时,path/domain这几个选项一定要旧cookie 保持一样。否则不会修改旧值,而是添加了一个新的 cookie。
删除 cookie
删除一个cookie 也挺简单,也是重新赋值,只要将这个新cookie的expires 选项设置为一个过去的时间点就行了。但同样要注意,path/domain/这几个选项一定要旧cookie 保持一样。
cookie 编码
cookie其实是个字符串,但这个字符串中逗号、分号、空格被当做了特殊符号。所以当cookie的 key 和 value 中含有这3个特殊字符时,需要对其进行额外编码,一般会用escape进行编码,读取时用unescape进行解码;当然也可以用encodeURIComponent/decodeURIComponent或者encodeURI/decodeURI(三者的区别可以参考这篇文章)。
var key = escape("name;value");
var value = escape("this is a value contain , and ;");
document.cookie= key + "=" + value + "; expires=Thu, 26 Feb 2116 11:50:25 GMT; domain=sankuai.com; path=/";
跨域请求中 cookie
之前在介绍 XHR 的一篇文章里面提过:默认情况下,在发生跨域时,cookie 作为一种 credential 信息是不会被传送到服务端的。必须要进行额外设置才可以。具体原因和如何设置可以参考我的这篇文章:你真的会使用XMLHttpRequest吗?
另外,关于跨域资源共享 CORS极力推荐大家阅读阮一峰老师的这篇 跨域资源共享 CORS 详解。
其他补充
什么时候 cookie 会被覆盖:name/domain/path 这3个字段都相同的时候;
-
如果显式设置了 domain,则设置成什么,浏览器就存成什么;但如果没有显式设置,则浏览器会自动取 url 的 host 作为 domain 值;
新的规范中,显式设置 domain 时,如果 value 最前面带点,则浏览器处理时会将这个点去掉,所以最后浏览器存的就是没有点的(注意:但目前大多数浏览器并未全部这么实现)
前面带点‘.’和不带点‘.’有啥区别:
带点:任何 subdomain 都可以访问,包括父 domain
不带点:只有完全一样的域名才能访问,subdomain 不能(但在 IE 下比较特殊,它支持 subdomain 访问)
原文:聊一聊 cookie
Cookie的介绍及使用的更多相关文章
- JMeter 配置元件之HTTP Cookie Manager 介绍
配置元件之HTTP Cookie Manager 介绍 by:授客 QQ:1033553122 测试环境 apache-jmeter-2.13 1. Cookie管理器介绍 Cookie Ma ...
- Session&Cookie 的介绍和使用
Session介绍与使用 1.Session基本介绍 Session:在计算机中,尤其是在网络应用中,称为“会话控制”.Session 对象存储特定用户会话所需的属性及配置信息.这样,当用户在应用程序 ...
- 转:Http协议中Cookie详细介绍
Http协议中Cookie详细介绍 Cookie总是保存在客户端中,按在客户端中的存储位置,可分为内存Cookie和硬盘Cookie.内存Cookie由浏览器维护,保存在内存中,浏览器关闭后就消失了, ...
- localStorage , sessionStorage ,cookie 使用介绍
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Cookie的介绍
Cookie是某些站点为了辨别用户身份而存在用户本地终端上的数据.Cookie总是保存在client中,可分为内存 Cookie和硬盘Cookie,而依照时间划分.又能够分为非持久Cookie和持久C ...
- session与cookie的介绍和两者的区别之其相互的关系
转:https://blog.csdn.net/weixin_37196194/article/details/55806366 本文分别对Cookie与Session做一个介绍和总结,并分别对两个知 ...
- 【转】asp.net中的cookie使用介绍
来源:http://www.jb51.net/article/30398.htm 一.cookie导读,理解什么是cookie 1.什么是cookie:cookie是一种能够让网站服务器把少量数据(4 ...
- httpclient cookie使用介绍
COOKIE的处理 session的保持是通过cookie来维持的,所以如果用户有勾选X天免登陆,这个session就X天内一直有效,就是通过这个cookie来维持. 如果没有选中x天免登陆,基本上就 ...
- httpclient cookie相关介绍
http状态管理 cookie是HTTP代理和目标服务器可以交流保持回话的状态信息的令牌或短包. httpclient使用Cookie接口来代表抽象的cookie令牌,在它的简单形式中http的coo ...
随机推荐
- 常用的百度API地图操作
常用的百度API地图操作,包括模糊搜索,放大缩小,并支持移动端 效果图如下 完整代码: http://download.csdn.net/detail/jine515073/8778167
- namp命令详解
我将用两个不同的部分来涵盖大部分NMAP的使用方法,这是nmap关键的第一部分.在下面的设置中,我使用两台已关闭防火墙的服务器来测试Nmap命令的工作情况. 192.168.0.100 – serve ...
- 在传统以太网中,为什么要有最小帧长度(64 bytes)和最大帧长度(1500 bytes)的限制?
遇到的问题:以太网的数据帧封装如下图所示,包含在IP数据报中的数据部分最长应该是( )字节? A.1434 B.1460 C.1480 D.1500 答案:C 原因: 以太网(IEEE 802.3)帧 ...
- 关于添加图片到svg中,rails下使用js, 用parseFloat来调整force.on时的位置
注意在代码中用/表示路径...windows中file才是\ 1.<image xlink:href=<%= asset_path 'vnet/virtual_switch.png' %& ...
- 让IE6支持min-height,max-height等的方法
1.IE6支持max-height解决方法 IE6支持最大高度解决CSS代码:.yangshi{max-height:1000px;_height:expression((document.do ...
- 重点:怎样正确的使用QThread类(注:包括推荐使用QThread线程的新方法QObject::moveToThread)
背景描述: 以前,继承 QThread 重新实现 run() 函数是使用 QThread唯一推荐的使用方法.这是相当直观和易于使用的.但是在工作线程中使用槽机制和Qt事件循环时,一些用户使用错了.Qt ...
- HBase二级索引方案总结
转自:http://blog.sina.com.cn/s/blog_4a1f59bf01018apd.html 附hbase如何创建二级索引以及创建二级索引实例:http://www.aboutyun ...
- fanqiang_bak
- VS2010 快捷键设置,快速编码1
全屏:Shift+Alt+Enter注释选定内容:Ctrl+E+C/Crtr+E+U代码格式化:ctrl+E+F VS2008 使用小技巧——快捷键1. 怎样调整代码排版的格式?选择:编辑—>高 ...
- (转)windows下编译最新的x264
二:<windows下编译最新的x264> X264更新的比较快,每天都有更新,但算法模块,基本结构是没有多大变化的.x264都是用C语言写的包括C99,但C99语法是在VC中是没法用的( ...