Cookie 没你不行

前言:

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

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 和http协议 (服务端操作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是谁写的,什么时候将会过期。

Cookie 和 javascript (客户端操作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 和 Asp.Net 中的  System.Web.HttpCookie

不同服务端代码中对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" />

HttpWebRequest 和 Cookie

工作中,除了浏览器发起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最核心的应用应该就是作为会话机制了,正如前言中提到的,浏览器停掉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

资料

Cookie 没你不行的更多相关文章

  1. session & cookie(li)

    Session & Cookie 一.定义 Session,用户在浏览某个网站时,从进入网站到浏览器关闭所经过的这段时间,也就是用户浏览这个网站所花费的时间.Cookie,由服务器端生成,发送 ...

  2. 进阶——scrapy登录豆瓣解决cookie传递问题并爬取用户参加过的同城活动©seven_clear

    最近在用scrapy重写以前的爬虫,由于豆瓣的某些信息要登录后才有权限查看,故要实现登录功能.豆瓣登录偶尔需要输入验证码,这个在以前写的爬虫里解决了验证码的问题,所以只要搞清楚scrapy怎么提交表单 ...

  3. Cookie中图片的浏览记录与cookie读取servle时路径的设置(文字描述)

    public class ShowServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpSer ...

  4. vue.js设置、获取、删除cookie

    项目需要前端获取后台返回的cookie,并以此作判断.我是在main.js入口文件下使用的 具体代码: new Vue({ el: '#app', router, template: '<App ...

  5. 向后台提交数据:利用cookie加session提交更多数据,

    个人逻辑,可能考虑不全面,各位看到后留言,我修改啊 实现效果:浏览器第一次访问提交用户名,后台验证通过,生成随机字符串,和用户名组成字典,保存到服务器,把随机字符串设置成cookie发给浏览器,同一个 ...

  6. 如何知道网页浏览器cookie是什么?

    一直有网友问网页cookie如何获取,其实想知道自己访问网页时的cookie没那么难,用Chrome内核浏览器的debug功能就能看到,怎么查看呢?随ytkah一起来看看吧! 打开网页,按F12键,选 ...

  7. [py]flask操作cookie&django的seesion和cookie机制

    浏览器同源策略(same-origin policy) csrf攻击防御核心点总结 django的cookie和session操作-7天免登录 flask操作cookie&django的see ...

  8. Cookie、Session 和 Token区别

    1 Cookie.Session 和 Token 都是用来做持久化处理的,目的就是让客户端和服务端相互认识.Http 请求默认是不持久的没有状态的,谁也不认识谁.   2 Cookie: 是存放在客户 ...

  9. Cookie技术

    u  常用的API 创建Cookie对象 Cookie(String name, String value)    ->以指定数据创建Cookie对象 设置Cookie对象 void setMa ...

随机推荐

  1. select2的远程加载非分页实例

    $("#c01-select").select2({ ajax: { url: "data.json", dataType: 'json', delay: 25 ...

  2. 如何让IntPtr指向一块内存,以及托管内存与非托管内存的相互转化

    IntPtr idp= IntPtr.Zero; StringBuilder idata = new StringBuilder("000000"); string idata = ...

  3. 求斐波那契数列第n位的几种实现方式及性能对比(c#语言)

    在每一种编程语言里,斐波那契数列的计算方式都是一个经典的话题.它可能有很多种计算方式,例如:递归.迭代.数学公式.哪种算法最容易理解,哪种算法是性能最好的呢? 这里给大家分享一下我对它的研究和总结:下 ...

  4. Keras实现MNIST分类

      仅仅为了学习Keras的使用,使用一个四层的全连接网络对MNIST数据集进行分类,网络模型各层结点数为:784: 256: 128 : 10:   使用整体数据集的75%作为训练集,25%作为测试 ...

  5. js call apply bind

    call.apply.bindcat.call(dog, a, b) == cat.apply(dog, [a, b]) == (cat.bind(dog, a, b))() 1.作用 改变函数内的t ...

  6. cf777D(贪心&&c_str()函数)

    题目链接:http://codeforces.com/contest/777/problem/D 题意:给出n行以#开头的字符串,从原字符串尾部删除尽量少的字符串,使其为非降序排列. 思路:我们可以从 ...

  7. 基于SpringBoot构建分模块项目

    前言 步骤过于详细,多图慎入!!! 假设一个场景,要开发一个4s店维修部的办公系统,其功能有:前台接待,维修抢单,财务结算,库存管理.于是我们创建一个项目balabalabala写完交工. 一段时间后 ...

  8. 根据经纬度反向地理编译出地址信息(如果报错:Error Domain=kCLErrorDomain Code=8 "(null)")

    注意:Error Domain=kCLErrorDomain Code=8 "(null)" 如果出现这个错误  一定是 经纬度有问题   一定是 经纬度有问题 一定是 经纬度有问 ...

  9. Luogu P1155 双栈排序 图论?模拟吧。。

    今天想做做图论,于是点开了这道题....(是二分图染色然而我没看出来) 四种操作及条件: 1. s1.push() 需满足 待push的元素小于栈顶 && { 若在原序列中,待push ...

  10. 长春理工大学第十四届程序设计竞赛(重现赛)L.Homework Stream

    链接:https://ac.nowcoder.com/acm/contest/912/L 题意: 作为大珩班尖子生,小r每天有很多作业要完成,例如工图.工图和工图. 很显然,做作业是要有顺序的.作业之 ...