近段时间都是在更新前端学习相关的文章,今天来学习和总结一下一个web通用知识: 浏览器缓存,Cookie和Session。这玩意对前端的性能优化也有一定作用,应该属于前端必须掌握的知识之一了。
缓存
在说这些之前,先说说浏览器的缓存。为什么会出现浏览器的缓存技术?不想下东西呗。同样的东西,我每次请求都要下一次,不管是从用户体验还是速度的方面考虑,都非常的僵硬。于是聪明的前端——哦不,浏览器设计者就想到了增加缓存这个东西。
前端想要自己控制缓存,可以在header上设置cache control(Link至MDN,以下部分内容来自MDN)。不算非标准的拓展命令,可以使用的属性值为以下:
缓存请求指令:
Cache-Control: max-age=<seconds>、max-stale[=<seconds>]、 min-fresh=<seconds>、 no-cache
、no-store、 no-transform、 only-if-cached
缓存响应指令:
Cache-control: must-revalidate、no-cache、no-store、no-transform、 public、 private、proxy-revalidate、 max-age=<seconds>、 s-maxage=<seconds>
一个个说的话就太麻烦了,还是直接看MDN比较好。这里我画一个简单的思维导图做辅助记忆用。
http://ooibweb9s.bkt.clouddn.com//17-6-19/65594827.jpg
看图细心的话应该能够发现,图中有一个s-maxage,对它的设置会覆盖maxage和Expire。Expire是什么?这就是我们能够在Header中设置的另外一个值。将Expires-cache contrl设置为一个时间,那么只要当前时间没有到这个时间,我们所有对服务器进行的请求都将不被接受转而直接走硬盘。(Expire的解释在MDN上没有中文,我认为应该直接翻译为“过期时间”?)
但是Expire有一个小小的问题,就是这个时间怎么来。要知道,浏览器的取时间方法(比如getTime)都是直接取得系统时间,这样就带来一个问题。根据客户端信息不可靠原则,如果我本地的时间错乱(比如我这种装了双系统然后Linux每次都会莫名改写windows时间的),那么Expire就形同虚设。所以嘛,一般不推荐使用Expire.
我们还能够设置的一个属性则是Last-Modified。如果设置了Last-Modified,那么它将默认保存缓存的内容300S。
Cookie
Cookie是啥我想我就不需要解释了,最简单的Cookie设置方法就是document.cookie/Cookies.set方法。在Set Cookies以后,对相同域名的所有请求都会带上这个Cookie回传。Cookie一般分为两种类型,分别为非持久Cookie(内存Cookie)和持久Cookie(硬盘Cookie)。内存Cookie由浏览器维护,保存在内存中,浏览器关闭后就消失了,而硬盘Cookie则有一个过期时间,过期时间内是持续有效的。
为什么要有Cookie?
因为HTTP协议是无状态的,服务器无法记录用户上一次的操作,这样就造成了交互上的阻碍。而Cookie就可以做到绕开HTTP的无状态。服务器借由从Cookie中读取包含的信息,借以维护用户和服务器会话中的状态。(比如购物/登录)。
Cookie的路径
Cookie一般都是由于用户访问一个页面才产生的,但是我们会遇到一个问题——并不是只有在创建Cookie的页面才需要访问这个Cookie。如果出于安全考虑,只有与创建Cookie的页面出于同一个目录或在创建Cookie页面的子目录下的网页才可以访问。
那么这样就又会带来一个问题:如果者说我希望其父级乃至整个网页都能够使用Cookie,怎么做呢?
可以这样:
document.cookie="userName=CoderMageFox;path=/";
Cookie的域
路径问题解决了,又一个问题摆在了面前。如果我们在同一个主域下有不同的域名(如img.codermagefox.com和test.codermagefox.com)那么如何互相访问呢?要知道,这个需求的场景相当多。这个时候,我们可以选择指定可访问Cookie的主机名来进行设置。
document.cookie="name=codermagefox;domain=codermagefox.com path=/;"
这样就可以解决啦。
Cookie的缺陷
(以下引用自MDN)
1.Cookie会被附加在每个HTTP请求中,所以无形中增加了流量。
2.由于在HTTP请求中的Cookie是明文传递的,所以安全性成问题。(除非用HTTPS)
3.Cookie的大小限制在4KB左右。对于复杂的存储需求来说是不够用的。[3]
然而我在翻阅《JavaScript权威指南》的时候发现了一点,现代浏览器遵循的HTTP标准是RFC2965。
书上原文:
而这个标准中对于这一段是这么写的:
5.3 Implementation Limits
Practical user agent implementations have limits on the number and
size of cookies that they can store. In general, user agents' cookie
support should have no fixed limits. They should strive to store as
many frequently-used cookies as possible. Furthermore, general-use
user agents SHOULD provide each of the following minimum capabilities
individually, although not necessarily simultaneously:
* at least 300 cookies
* at least 4096 bytes per cookie (as measured by the characters
that comprise the cookie non-terminal in the syntax description
of the Set-Cookie2 header, and as received in the Set-Cookie2
header)
* at least 20 cookies per unique host or domain name
看到这里我有点懵逼了。不是说at least 吗?所以说这些标准其实是浏览器自己定的而不是文档规定的?这个坑我暂时没弄明白,以后弄明白了再回来填。
Session
正如同上面所说,HTTP的传输有一个很大的问题,就是明文传输。明文传输会导致一个什么问题?我可以抓包来获取很多用户信息(比如使用WireShark\Fiddle等工具)而且HTTP请求是可以篡改的,并且十分容易篡改。又根据客户端信息不可靠原则,我们需要一个东西来验证用户的身份怎么办呢?
这个时候,Session就出马了。Session也可以做到Cookie的部分功能,不过,Session是保存在服务器上的。服务端的信息无法随便篡改,所以Session可以做到可靠。具体的做法一般是服务端和客户端之间不传输明文数据,而是传输一段经过特殊加密的密文,密文对应的服务器硬盘数据中才是真实的数据。这段数据在Session激活后从服务器磁盘中取出到内存中,再返回给浏览器。
需要注意的是,Session是一种抽象的概念,开发者为了实现中断和继续等操作,将 user agent 和 server 之间一对一的交互,抽象为“会话”,进而衍生出“会话状态”。而而 cookie 是一个实际存在的东西,http 协议中定义在 header 中的字段。Session可以被认为是一种Cookie的后端无状态实现。
当然,现在很多大流量的网站使用的一般是Secret Cookie,这又是另外一种做法了。
便于记忆的思维导图:
写了这么多,对于Cookie/Session的理解算是有一些了。今天收获不错,Nice!