Cookie 没你不行

Cookie 没你不行

前言:

你知道吗,当有人悄悄的禁用了你浏览器的cookie,一场灾难将会发生,如果你不是一个开发人员,那更是灾难。 
笔者在写这篇文章前做了下实验,BAT全部登录不了,只有baidu给了个人性化的提示:Alt text 
既然cookie如此重要,你真的对它了解吗?

起源

讲这个还是得先讲讲cookie是如何诞生的,因为HTTP协议是无状态的,即服务器不知道用户上一次做了什么,这严重阻碍了交互式Web应用程序的实现。于是有这么一个人,网景公司的前雇员卢·蒙特利在1993年3月的发明了cookie。最初在1997年2月定义于 RFC 2109,后来有两次更新,于2000年10月的RFC2965和2011年4月RFC6265。 
你可以发现这几个文档的标题都是: HTTP State Management Mechanism (http 状态管理机制) 。 
讲到这里,有没有觉得cookie 是一个神奇的存在, 1993年发明的,一直用到现在 ,虽然互联网技术日新月异,但它还是保留下来,并且不可或缺,rfc文档 也有两次更新 。

到底是什么?

Cookie 是服务器保存在浏览器的一小段文本信息。这是个纯文本的信息,并且按照协议规定的格式来存储 。浏览器每次向服务器发出请求,就会自动附上这段信息,于是Web 服务器就可以使用这些信息来识别不同的用户 。生活中我们使用的大部分需要登录的网站,登录成功后都会设置一个cookie到浏览器,只要这个cookie 存在,用户就可以浏览网站的任意页面,手动清理掉这个cookie,就相当于退出登录。 这也就是为什么前言中会出现:如果禁用浏览器cookie功能,大部分网站就无法登录,无法使用需要登录后才能使用的功能了。

使用场景

会话(session)管理:保存登录、购物车等需要记录的信息。 
个性化:保存用户的偏好,比如网页的字体大小、背景色、地域等等。 
追踪:记录和分析用户行为,广告。

这里有必要提一下,浏览器对单个cookie的大小,一个网站的cookie个数,总的大小和个数都有限制,其实cookie不适合用来作为大量数据的客户端存储,如过需要这个功能,可以使用浏览器的Local Storage 、IndexDB等新的功能来替代,这里就不做延展。

cookie的缺陷 
Cookie会被附加在每个HTTP请求中,所以无形中增加了流量。 
由于在HTTP请求中的Cookie是明文传递的,所以安全性成问题,除非用HTTPS。 
Cookie的大小限制在4KB左右,数量在20左右,对于复杂的存储需求来说是不够用的。

如何使用cookie

Cookie实际上是由浏览器在管理(浏览器放出接口),这个问题就变成如何指挥浏览器增删改查cookie ,我们知道浏览器是遵守http协议的,还有另一方web服务端也是遵守的。我们可以通过这个来指挥浏览器操作cookie。

服务端要操作cookie是通过响应头:Set-Cookie , 浏览器接受到这个响应头 ,就相当于收到命令去操作cookie ,具体是添加cookie ,删除cookie 还是修改cookie 要看后面的值 ,一个Set-Cookie 响应头自能操作一个cookie ,一个响应可以有多个Set-Cookie响应头 ,这样一次响应就能操作多个cookie, 
响应头中的cookie实例: 
Set-Cookie:ykjjdc=c89e252fb3ce3cf203f; domain=.jjw.com; expires=Mon, 21-Mar-2118 07:00:11 GMT; path=/ 
用 “;” 分隔的字符串,每一段基本是一个键值对。 
服务端要获取cookie 是通过 请求头: Cookie ,http协议规定浏览器每次发起一个请求,要筛选符合要求的cookie(比如域相同,路径相同,没过期等)放在请求头Cookie中 传递给服务端 。 
请求头中的Cookie实例: 
Cookie: cna=UfdnD69NHXgE8g; UM_distinctid=16223df34200 
可以到也是用 “;” 分隔的字符串, 没一段就是一个cookie ,忽略了cookie的其他属性,也就是说服务端不知道这个cookie是谁写的,什么时候将会过期。

document.cookie 是客户端读写cookie的唯一接口 ,这个属性可读可写 。 
读的情况下,返回当前脚本路径下所有的cookie(不包含属性包好httponly的),按照相关性排序(解决不同路径下相同名字cookie的问题)。读出来的示例: 
iddc=fsfea; fsf=3; yssskjjdc=ssfe; ykjjdc=fsa

写的情况下,一次只能写一个cookie,不会覆盖已有cookie ,根据你写的内容,会出现 添加一个cookie ,修改一个cookie ,删除一个cookie等不同的结果 。 
写的示例如下:

document.cookie = "foo=bar; expires=Fri, 31 Dec 2020 23:59:59 GMT";

可以看出都是对字符串的处理,这种处理容易出错,目前比较流行的cookie帮助类有 jquery.cookie.js 和yui中的对cookie的相关函数。可以方便的读写cookie。

不同服务端代码中对cookie封装的原理就是 基于 http协议中的cookie机制 ,上文中有提到,asp.net 也不例外。 
asp.net 中有一个类 System.Web.HttpCookie 来对应cookie ,我们来看看他的结构

HttpCookie 属性 cookie 原生属性 描述
Domain domain 获取或设置要将与 cookie 相关联的域。
Expires expires 获取或设置的过期日期和时间的 cookie。
HasKeys 获取一个值,该值指示 cookie 是否有子项。subcookies应用
HttpOnly httponly 获取或设置一个值,指定 cookie 是由客户端脚本访问。
Name name 获取或设置 cookie 的名称。
Path path 获取或设置要与当前 cookie 传输的虚拟路径。
Secure secure 获取或设置一个值,该值指示是否传输,即通过 HTTPS 仅使用安全套接字层 (SSL)-的 cookie。
Value value 获取或设置一个单独的 cookie 值。
Values 获取包含在一个 cookie 对象内的键/值对的集合。subcookies,解决cookie个数过多问题
max-age 对 expires属性的补充 ,存在浏览器兼容性问题
host-only 强制域完全一致才可访问

通过上表我们可以看到 ,原生cookie的属性基本和aspnet 中的一致。 
我们可以通过Request.Cookies 得到请求头中的cookie ,并且可以很方便的拿到对应的值 , 
(有兴趣的朋友可以研究下 ,有相同的cookie名时服务端的取值情况 )。

在aspnet 中服务端可以通过下面的对象或者语法方便的操作cookie 。

Response.AppendCookie()
Response.AppendHeader("Set-Cookie" ,"iron=fage");
Response.SetCookie()
Response.Cookie.Add()

但是笔者认为这个设计还不如 JavaScript中 cookie 的操作设计,一个属性增删改查全是它 。 
这样的封装设计干扰了程序员对cookie的学习了解。

web.config 关于cookie的全局配置节点 , 你可以指定cookie的域 ,当然这个域必须和地址栏中的主域一致; 也可以为了安全起见配置httpOnlyCookies 使默认输出的cookie 都是js不能读取操作的 ; 还可以配置 requireSSL 是浏览器只有在https地址上发送这个cookie (这个的前提也是当前协议是用的https)。

<httpCookies domain="String"
httpOnlyCookies="true|false"
requireSSL="true|false" />

工作中,除了浏览器发起http请求外, 还有一种情况是自己编写代码来发起http请求,比如对第三方http接口的请求。

CookieContainer cookieContainer = new CookieContainer();
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "GET";
request.CookieContainer = cookieContainer;//这个属性用来传递cookie
 
using( WebResponse response = request.GetResponse() ) {
using( StreamReader reader = new StreamReader(response.GetResponseStream(), encoding) ) {
return reader.ReadToEnd();
}
}
//执行上面的代码后,如果http响应中有cookie,将会追加到 cookieContainer ;

Cookie最核心的应用应该就是作为会话机制了,正如前言中提到的,浏览器停掉cookie ,大部分网站都无法登录的数据。 其实 asp.net 中的 Session[“”] 默认配置下,就依赖于cookie ,会在客户端用cookie存储一个sessionid 。

Cookie最常见的应用还有 ,记录用户的使用偏好 ,比如用户 常用城市, 语言 ,网站主题,字体等 , 当然这些都可以存储服务端和用户信息关联 ,但是如果网站不需要登录,这些数据存储在服务端就不合适了。

还有吗?

工具

浏览器本身就会提供cookie 的开关配置,用户可以根据自己需要来开启或者关闭,或者开启部分网站,关闭部分网站等设置 。 
浏览器也会提供cookie的管理工具 , 但是大都不是很好用 。 chrome 内核浏览器 的开发人员工具可以很方便的查看cookie 但是管理就不是很便利了 。 
浏览器插件是解决这个问题的终极方案, EditThisCookie 这款浏览器插件是个不错的选择。

Q&A

  • 如果你需要写一个浏览器,你需要对cookie 做哪些处理
  • 接口化开发,对于接口的响应中的cookie如何处理 。
  • 除了通过 set-Cookie ,JavaScript 操作cookie ,还有其他方式吗
  • 向图片,css ,js 发出的请求 会携带cookie 吗
  • 说说cookie 的缺点
  • 对我们工作的启发 ?

Thanks

资料

posted @ 2018-03-22 19:21  地菜  阅读(1670)  评论(0编辑  收藏  举报