Cookie&Session、LocalStorage&SessionStorage、HTTP缓存
<pre>标签可以保留回车和空格等你怎么写它就怎么展示的内容
cookie
cookie可以看作是一种设置,允许浏览器在电脑本地硬盘的某一个隐蔽的地方开发一块存储空间,用来存放某些特定的内容。
如果在服务器端设置了允许使用cookie,那么,之后浏览器每次向同域名服务器发送请求,都会带上cookie,意味着每发送一次请求,浏览器都会把存在本地硬盘那某一个隐蔽地方里的文件发送给服务器,交由服务器处理。
通常,我们习惯将用户的登陆信息存放在cookie里,所以,服务器能够通过浏览器发送给它的cookie判断用户注册了没有?、用户名密码是否正确?、用户名密码是否匹配?、该用户多少等级了?。。。由此,返回相应的网页内容。
在这里为什么总感觉难以理解??这是因为,cookie的概念要涉及服务器和浏览器,两者感觉交织在一起。所以,有必要理清一下思路:cookie的基本操作流程。
cookie的基本操作流程
- 第一,浏览器会发送一个请求,将一个东西(对象、哈希、数组,随便你怎么叫)发送给服务器
- 第二,服务器将发送给它的这个东西进行处理,得到的结果以字符串的形式、通过
Set-Cookie响应头返回给浏览器,该字符串称之为cookie - 第三,现在浏览器得到
Set-Cookie响应头并获允使用cookie,之后,用户每次向相同域名网站的服务器发送的请求,都会带上该cookie - 第四,每一次请求,服务器可以读取
cookie,获取cookie中包含的信息(用户资料、特定页面信息等),然后向浏览器返回相应的内容
cookie示例
前端代码:
$.post('/sign_in', hash)
.then((response)=>{
window.location.href = '/index.html'
}, (request)=>{
alert('邮箱与密码不匹配')
})使用node.js写的后端代码示意:
if(path === '/sign_in' && method === 'post'){
//your code
response.setHeader('Set-Cookie','sign_in_email=${email}'; HttpOnly; Max-Age=3000');
//your code
}else if(path === '/index.html'){
//your code
let cookies = request.headers.cookie;
//your code
}在上述示例代码中,
- 第一步,前端代码(浏览器)使用
jquery的post()方法向服务器朝/sign_in路径发送了一个请求,将变量hash传给了服务器。 - 第二步,后端代码(服务器)在
//your code里对变量hash处理后,将处理结果变成'sign_in_email=${email}'的字符串(其中${email}表示变量email代表的数据),然后设置了响应头Set-Cookie返回给浏览器,并加诸了像HttpOnly、Max-Age等各类设置(详细说明请参见https://developer.mozilla.org...)。 - 第三步,浏览器收到了服务器返回的响应头
Set-Cookie和cookie(字符串),说明请求成功了,会将网页重定向为/index.html(这里使用了promise:.then((response)=>{window.location.href = '/index.html')。所以浏览器又向服务器发送了一次请求。这次请求会带上cookie - 第四步,服务器又收到了一次请求,这次请求的路径是
/index.html,并且带有cookie。那么,服务器可以使用request.headers.cookie来获取cookie,然后在//your code里处理后,在//your code里给浏览器返回相应的页面
cookie的几个特点
不同浏览器之间的
cookie不通用这就好像Firfox的www.segmentfault.com不是chorme的www.segmentfault.com
cookie存在硬盘的某一个神秘文件里cookie很容易被修改,用户可以自己进入浏览器控制台修改cookie看到下图,Firfox的控制台进入存储、进入Cookies,我们修改了两个值,并且刷新后,一个值会变回来,一个值没有变回来

cookie的有效期默认由浏览器自己决定,当然可以通过后端设置cookie的保存时间当然,不同后端语法不一样写法不一样,通常都是设定Max-Age或者Expires属性
详细可以参见:
Set-Cookie:https://developer.mozilla.org...
HTTP cookies:https://developer.mozilla.org...
cookie应用
可想而知,cookie最常用的就是注册&登陆啦~~~
- 先在浏览器注册,注册好了就向浏览器发送请求,报告!请求注册成功页面!!
- 服务器检查下自己的数据库,这是个新兵,存下来存下来,然后返回包含新兵狗牌的
cookie和注册成功页面 - 这个
cookie有时间限制,在这个时间段里,新兵访问服务器不用再报告了(浏览器发送请求一直带着这个cookie) - 过了这个时间段,
cookie失效了(浏览器发送请求不带上cookie了),不好意思,请证明你自己(登陆,并获得新的老兵狗牌的cookie和登陆成功页面)

session
cookie好啊,可以让服务器知道我们是VIP用户了,不过因为能被轻松的查看并且容易被篡改,所以引出新概念session,而session更像是一种技术,而不是一种设置
从前,服务器直接将用户信息存在cookie里,现在,服务器将sessionId放在cookie里,再通过sessionId到session表里查找sessionId对应的相关内容。
那为什么就防止了cookie容易被篡改的问题呢?因为sessionId里存放的是随机数Math.random(),你取个很多位的随机数,那普通人就没办法猜了,完全不知道哪个随机数对应的是用户、哪个不是。
那要是sessionId被删了呢?那没办法了,只能重新登陆,意味着重新提交、重新分配随机数。

看上图,上图是在chorme里控制台的Application → Storage → Cookies选项,看到服务器向浏览器发送了带有sessionId的cookie,一个随机数,之后,浏览器再向服务器发送请求就会带上这个cookie
session其实本质上就是cookie,只不过加了一个中间量sessionId,我们还是来看看session的基本流程
session的基本流程
- 第一,浏览器会发送一个请求,将一个东西(对象、哈希、数组,随便你怎么叫)发送给服务器
- 第二,服务器有一个哈希叫作
session,该哈希的key就是sessionId(随机数)、value是第一步里送送给服务器的东西的处理结果:一个字符串,以前的cookie - 第三,服务器会设置响应头
Set-Sookie,将sessionId(随机数)通过cookie的形式发送给浏览器 - 第四,之后,浏览器每请求一次服务器,就会带上这个含有
sessionId的cookie,服务器就会读取sessionId,并在session哈希里查找sessionId对应的值,然后作出相应的操作
session示例
前端代码:
$.post('/sign_in', hash)
.then((response)=>{
window.location.href = '/index.html'
}, (request)=>{
alert('邮箱与密码不匹配')
})使用node.js写的后端代码示意:
let sessions = {};
if(path === '/sign_in' && method === 'post'){
//your code
let sessionId = Math.random()*100000000;
session[sessionId] = {sign_in_email:email};
response.setHeader('Set-Cookie','sessionId=${sessionId}'; HttpOnly; Max-Age=3000');
//your code
}else if(path === '/index.html'){
//your code
let cookies = request.headers.cookie;
let sessionId = ;
let email = session[sessionId];
//your code
}上面发生了什么可以通过和cookie作对比知道:
- 第一,在服务器我们设置了一个哈希
let session = {} - 第二,在服务器我们生成一个随机数
sessionId作为session的键,获取email作为该键的值 - 第三,服务器设置
Set-Cookie响应头,将sessionId作为cookie传回给浏览器 - 第四,浏览器请求成功,网页重定向为
/index.html,重新发送请求,带有cookie,其中带有sessionId - 第五,服务器接收到
cookie,得到sessionId,搜寻session,获得相应email,在//your code里返回相应内容
localStorage
localStorage是HTML5发布的新api。它是一个哈希,作用就是字面意思,本地存储,只不过这里的本地指的是浏览器。
请参考:https://developer.mozilla.org...
用法也不难,你可以通过localStorage自己的方法往这个哈希里面的数据,再通过localStorage自己的方法调用里面的数据。
localStorage的方法
设置一个
localStorage值:setItemlocalStorage.setItem("cat","rainy");获取一个
localStorage值:getItemvar cat = localStorage.getItem("cat");移除一个
localStorage值:removeItemlocalStorage.removeItem("cat");清除所有
localStorage值:clearlocalStorage.clear();
查看
localStorage哈希:localStorageconsole.log(localStorage);
localStorage的特点
- 和
http无关,意味着它不会存在于浏览器和服务器之间的通信,请求响应时不会带上localStorage的值 - 只有相同域名的页面才能互相读取
localStorage - 当然,
localStorage是浏览器自己的存储空间,所以不同浏览器之间也是不能相互读取的 - 当页面刷新或者关闭后,
localStorage里的值也不会消失,所以叫local呀~
localStorage的物理地址存在硬盘里的某个文件里- 每个域名的
localStorage最大存储空间都是浏览器自定的,一般在5MB左右,如果溢出就会有下面这样的提示
- 永久有效,除非手动清理
sessionStorage
此接口作用和localStorage一样样,也是开辟了一块地方供浏览器存储数据用。
请参考:https://developer.mozilla.org...
sessionStorage的方法请参考上一章localStorage的方法。请将localStorage都替换成为sessionStorage。
sessionStorage的特点请参考上一章localStorage的特点。唯一的区别在于sessionStorage在关闭页面后就被清空了。请看下动图。
小结
形象理解
cookie&session就好像要去游乐园(服务器)玩,你可以选择买票(登陆,获得
cookie)或者不买票(不登陆,随便逛逛),不买票只能玩一些项目(网页公共内容),买了票能解锁更多项目(网页私有内容)。那么关于这张票,如果实名认证的,你的姓名、身份证号都在上面,这是cookie的做法,如果票上面只有一个编号,游乐园需要通过编号查找数据库才能认证你,那这就是session的做法
cookie和session有啥区别?session是基于cookie实现的。session就是不直接将用户信息存放在cookie里,而是将sessionId放在cookie里传给服务器,服务器通过sessionId在session哈希里查找相应的值cookie和localStorage有啥区别?cookie会随着每一次请求发送给服务器,而localStorage则不会带给服务器,它是浏览器的一块存储地。另外,cookie一般只有5KB左右的大小,而localStorage一般则有5MB左右的大小sessionStorage和localStorage有啥区别?sessionStorage在页面关闭(会话结束)后就被全部清空,而localStorage则不会。- 作为前端,最好不要直接读/写
cookie。cookie的内容越多,发送给服务器的时间越长,影响请求时间,导致访问变慢。如果一般的数据,不需要特别发给服务器的,请使用localStorage
http缓存
Cache-Control
顾名思义,控制缓存
若服务器设置了该项设置,意味着页面将被放在缓存里,当浏览器需要请求服务器的时候,将不会将请求发送至服务器,而是直接调用缓存里的页面。
各类属性详细请参考:https://developer.mozilla.org...
请看下图,右侧浏览器Chorme向服务器Server请求/main.js,服务器Server返回浏览器Chorme一个Max-Age=30的Cache-Control的响应头。那么接下来的30s内,浏览器Chorme再向服务器Server请求/main.js,注意!!!必须是完全相同的URL!!!,会直接从缓存(内存)里调用main.js,直到过了30s从能再从服务器端获取main.js
Cache-Control的使用
前端代码:
$.post('/sign_in', hash)
.then((response)=>{
window.location.href = '/index.html'
}, (request)=>{
alert('邮箱与密码不匹配')
})使用Node.js写的后端:
if(path === '/sign_in' && method === 'post'){
//your code
response.setHeader("Cache-Control","max-age=30");
//your code
}上面的代码显示,在30s的时间内,任何以post方法向服务器/sign_in路径的请求,都不会被发送,而会直接调用缓存里/index.html的页面
Cache-Control的几个特点
- 通常首页请不要设置缓存,如果设置了,就意味着做任何操作后,页面都从缓存里调用,这样就不会再更新新的页面。
除去首页,其它资源可以设置为10年,300000000,3后面8个0
什么?10年?那需要更改了怎么办?
修改url
原来页面里引用的js例如说像这样:<script src="./myCatRainy.css"></script>
那么现在只需要改正这样:<script src="./myCatRainy.css?v=1"></script>
看出区别了吗?多了?/v=1,但是两个路径都调用的同一个文件- 同样,
Cache-Control控制的缓存的物理地址在硬盘里的某一个位置,浏览器会设置一个固定大小,多了就将之前的缓存清掉
Expires
曾经,我们使用Expires设置缓存控制响应头:
if(path === '/sign_in' && method === 'post'){
//your code
response.setHeader("Expires","Sun, 04 Feb 2018 14:00:05 GM");
//your code
}区别在于Expires设置的是过期时间点,且该过期时间点参考的是本地时间,本地时间会因为机器故障、人为修改等原因不尽相同。而Cache-Control设置的则是过期时间段
另外,如果同时设置了Cache-Control和Expires,Expires会被覆盖、会被忽略
ETag
MD5
全称:MD5信息摘要算法
英文:Message Digest Algorithm MD5
作用:比较两个文件的差异
原理:一个文件通过几个步骤将产生出一个128位(16字节)的散列值(hash value)
特点:两个文件,差异越小,算出来的MD5值差别越大
使用:专门生成MD5的软件,npm安装。。。
ETag
若需要启用ETag设置,服务器要设置ETag响应头,该响应头将服务器端的页面的MD5值返回给浏览器。这样,浏览器在下次请求的时候,会多提交一个请求头if-none-match,里面存放即是服务器响应回来的MD5值。如此,服务器能够对比自己现在的MD5和浏览器发送过来的MD5,如果一样就不用返回服务器端页面了,如果不一样才将服务器端的新页面返回给浏览器
ETag示例
前端代码:
$.post('/sign_in', hash)
.then((response)=>{
window.location.href = '/index.html'
}, (request)=>{
alert('邮箱与密码不匹配')
})使用Node.js写的后端:
if(path === '/sign_in' && method === 'post'){
//your code
let string = fs.readFileSync('./sign_in.html','utf-8');
let fileMD5 = md5(string);
let lastMD5 = request.headers['if-none-match'];
if(fileMD5 === lastMD5){
response.statusCode = 304;
}else{
response.setHeader("ETag",fileMD5);
response.write(string);
}
//your code
}来来来,看这里:
- 第一,浏览器的第一个请求是没有
if-none-match这个请求的,所以,服务器会设置一个响应头response.setHeader("ETag",fileMD5);,将服务器端页面的MD5返回给浏览器
- 第二,等浏览器再次发送请求的时候,就会多带上一个请求头
if-none-match
- 第三,看到后端代码,取到浏览器请求过来的MD5
let lastMD5 = request.headers['if-none-match'];,得到服务器端文件现在的MD5let fileMD5 = md5(string);(已经用npm安装过生成MD5的程序),如果相同,返回304if(fileMD5 === lastMD5){response.statusCode = 304;},如果不同,返回新的MD5和新的页面else{response.setHeader("ETag",fileMD5);response.write(string);}
Last-Modify
Last-Modify和ETag作用一样,用法也一样,唯一不同的地方是ETag返回的是一个MD5值,而Last-Modify返回的是一个时间点。也就是说,ETag对比浏览器和服务器页面的MD5,Last-Modify对比浏览器和服务器页面的时间点。
如果更新时间间隔较短,请选用ETag,更新时间中等,可以选用Last-Modify。当然,ETag优先级是要高于Last-Modify的。另外,Lsat-Modify不支持秒级别更新。这一段请参考:https://www.zhihu.com/questio...
小结
关于http缓存有下面几种控制:
Cache-Control:使用Max-Age设定缓存过期时间段Expires:直接设定缓存过期时间点ETag:对比两端文件的MD5值Last-Modify:对比两端文件的最后修改时间点