浏览器持久化存储与HTTP缓存
本文主要学习一些HTTP高级知识,例如
Session、LocalStorage、Cache-Control、Expires、ETag
主要是涉及到浏览器持久化存储和HTTP缓存的一些技术
Cookie自身存在问题,用户能随意篡改Cookie获得其它用户的隐私信息,为了解决这个问题出现了基于Cookie来实现的Session。
一 Session
Session
实质上就是一块内存,如果有需要可以存在硬盘上。
sessionId
使用Cookie
的时候,服务器会先个用户一个响应头,来设置Cookie
response.setHeader('Set-Cookie', `sign_in_email=${email}`)
response.statusCode = 200
通过sessionId
来改写响应头Set-Cookie
设置Cookie
let seesions ={}
// 在服务器端准备一个hash来存储session
...
let sessionId = Math.random()*100000
sessions[sessionId] = {sign_in_email: email}
response.setHeader('Set-Cookie', `sessionId=${sessionId}`)
response.statusCode = 200
在用户登录时,浏览器可以查看到响应头
再次访问该域名下的页面时Cookie
就可以利用sessionId
来得到用户隐私信息
使用随机数来做sessionId
,最终把这一串随机数暴露给用户。服务器通过Set-Cookie
给用户一个sessionId
,每次用户访问访问服务器的时候,服务器通过对应的sessionId
来读取sessions里的信息,就知道了用户的隐私信息了,安全是利用随机数保证的。
var sessions = {
sessionId: {sign_in_email: email},
}
二 持久化存储
1.localStorage
localStorage
是HTML5提供的API
window.localStorage
实质上是一个浏览器全局环境下的hash
表
存在c盘的一个文件里,大小一般为5m,不同浏览器大小不同
如何使用
存对象时用JSON
来存储,否则会被转换为字符串[Object Object]
// 1.添加键,值
localStorage.setItem('jsonString', JSON.stringify({name:'obj'}))
// 2.获得值
localStorage.getItem('jsonString')
//3.清空localStorage
localStorage.clear()
和其他变量的区别
在JavaScript脚本里的变量,会在页面关闭和刷新时就没有了,下一次打开的时候又重新生成。
localStorage
里的变量持久化存储可以再以后使用。
在有localstorage
前所有的变量在页面刷新的时候全部销毁,没有办法保存下来,每次都是新的
最典型的应用记录是否提示过用户
2. SessionStorage
和localStorage
特点基本相同;不同点为LocalStorage
若不清除就一直有效,SessionStorage
在用户关闭页面后(会话结束)就会失效。
三 总结
3.1 Cookie
- 服务器通过Set-Cookie头给客服端一串字符串
- 客户端每次访问
相同域名
的网页时,必须带上这短字符串 - 客户端要在一段时间内保存Cookie
- Cookie默认在用户关闭页面后就失效,后台代码可以设置Cookie的过期时间
- 大小大概在4kb左右
3.2 Session
- 将 SessionID(随机数)通过 Cookie 发给客户端
- 客户端访问服务器时,服务器读取 SessionID
- 通过 SessionID 我们可以得到对应用户的隐私信息,如 id、email
- 服务器有一块内存(哈希表)保存了所有 session
3.3 localStorage
- LocalStorage 跟 HTTP 无关,HTTP 不会带上 LocalStorage 的值
- 只有相同域名的页面才能互相读取 LocalStorage(没有同源那么严格)
- 每个域名 localStorage 最大存储量为 5Mb 左右(每个浏览器不一样)
- 常用场景:记录有没有提示过用户(没有用的信息,不能记录密码)
- LocalStorage 永久有效,除非用户清理
四 HTTP缓存
用于web性能优化,假如说我们要访问的的文件比较大,我们请求完之后,下载需要花很长时间,当我们刷新页面的时候,虽然文件没有任何更新,但是我们又从服务器端下载了一遍大文件,导致每次响应时间依然很长。我们可以利用HTTP缓存来进行性能优化。
4.1Cache-Control
如何设置缓存
通过max-age设置缓存有效时间
if (path === '/js/main.js'){
let string = fs.readFileSync('./js/main.js', 'utf8')
response.setHeader('Content-Type', 'application/javascript;charset=utf-8')
response.setHeader('Cache-Control', 'max-age=30')
response.write(string)
response.end()
}
以上在响应头里加上Cache-Contorl
,表示浏览器在30s内刷新页面也不会发起对main.js
的请求,在本地的内存硬盘里加载main.js
,加快浏览器的加载速度。
Cache-Contorl
让浏览器在一段时间内不访问服务器,而是从本地的内存和硬盘上拿到所需资源,连请求都没有,所以页面加载就十分快。
注意
- 在首页不能设置Cache-Control,我们刷一些论坛性质的或者新闻性质的网站,注重时效性,一般会把爆炸性的、高质量的内容放到首页去,如果我们看了一会,想刷新看看新的更新的内容,而你设了缓存,看到的还是10分钟之前的首页。
- 缓存尽量设置可能长的时间 ,如果一个文件长期不变,把它设为从缓存里面获得,知乎设置了32596169秒的有效时间,1年的时间。
如何更新缓存
开发者在入口处URL
进行改变,来重新请求更新,要升级就改变URL
需要更新设置查询参数 ?v=3 来重新加载 版本号
需要更新在入口处URL
更新,就会重新去加载最新的文件版本了。
...
...
当你更新代码之后,理论上只需要在URL上添加查询参数?V2
即可。
4.2Expires以前使用
如果有了cache-control
,Expires
会被忽略
Expires
响应头包含日期/时间, 即在此时候之后,响应过期。无效的日期,比如 0, 代表着过去的日期,即该资源已经过期。
如果在
Cache-Control
响应头设置了 "max-age" 或者 "s-max-age" 指令,那么Expires
头会被忽略。
response.serHeader('Expiers', 'GM时间')
什么时间缓存过期重新请求。
使用Expires要将时间转化为格林威治时间
var d = new Date() //Sat Feb 10 2018 11:18:54 GMT+0800 (CST)
d.toGMTString() //"Sat, 10 Feb 2018 03:18:54 GMT"
if (path === '/js/main.js'){
let string = fs.readFileSync('./js/main.js', 'utf8')
response.setHeader('Content-Type', 'application/javascript;charset=utf-8')
response.setHeader('Expires', 'Sat, 10 Feb 2018 03:18:54 GMT')
response.write(string)
response.end()
}
Expires
是基于用户电脑的本地时间,若用户本地时间有错,所有缓存就会有错。所以优先使用Cache-Control
4.3ETag
The ETag HTTP response header is an identifier for a specific version of a resource. It lets caches be more efficient and save bandwidth, as a web server does not need to resend a full response if the content has not changed. Additionally, etags help prevent simultaneous updates of a resource from overwriting each other ("mid-air collisions").
If the resource at a given URL changes, a new
Etag
value must be generated. A comparison of them can determine whether two representations of a resource are the same. Etags are therefore similar to fingerprints, and might also be used for tracking purposes by some servers. They might also be set to persist indefinitely by a tracking server.
- ETag HTTP响应头是对特定资源版本的识别
- 如果这个资源的URL改变了,一定会生成一个新的ETag值,一个检验会决定它们是否是同一资源。因此Etag有一点像资源的指纹。
md5一个摘要算法,用于检验文件是否相同,给文件一个版本号。
MD5引入
//terminal
npm install md5
...
//在server.js引入
var md5 = require('md5');
...
// terminal
MD5 (mian.js) = 2bb84jdhfrh294r492348frwa9322
如何设置ETag缓存未更改的资源
if (path === '/js/main.js'){
let string = fs.readFileSync('./js/main.js', 'utf8')
response.setHeader('Content-Type', 'application/javascript;charset=utf-8')
let flieMd5 = md5(string)
response.setHeader('ETag', flieMd5)
//response.setHeader('Expires', 'Sat, 10 Feb 2018 03:18:54 GMT')
response.write(string)
response.end()
}
浏览器响应头如下
再次刷新可以看到客服端发送的请求里会出现一个新的请求头If-None-Macth
服务器将客服端的ETag(If-None-Macth
的值)与其当前版本的ETag进行比较,如果两个值匹配,服务返回不带响应第四部分的响应,也就是没有响应体。就是未修改的304 Not Modified
状态
可以得知具体的实现如下
if (path === '/js/main.js'){
let string = fs.readFileSync('./js/main.js', 'utf8')
response.setHeader('Content-Type', 'application/javascript;charset=utf-8')
let flieMd5 = md5(string)
response.setHeader('ETag', flieMd5)
if(request.headers['if-none-match'] !== flieMd5) {
//有响应体,加载改变的资源
response.write(string)
}else{
//没有响应体
response.statusCode = 304
}
response.end()
}
304 Not Modified
HTTP 304 说明无需再次传输请求的内容,也就是说可以使用缓存的内容。这通常是在一些安全的方法(safe),例如
GET
或HEAD
或在请求中附带了头部信息:If-None-Match
或If-Modified-Since
。
304表示依然会有请求与响应,但是不会有响应的第四部分响应体。而是直接从本地的内存硬盘中获得。
五 常见题目
1.Cookie 和 Session 的区别
Cookie 保存在客户端,每次都随请求发送给 Server
Session 保存在 Server 的内存里,其 Session ID 是通过 Cookie 发送给客户端的
2.Cookie 和 LocalStorage 的区别
- window.LocalStorage实质上全局对象里的一个hash表,由HTML5提供的一个API,用于持久化存储;Cookie的大小一般在4k左右,LocalStorage的大小一般在5m左右不同浏览器大小不同
- Cookie属于HTTP内容,HTTP不会带上LocalStorage
3.LocalStorage 和 SessionStorage 的区别
LocalStorage若不清除就一直有效,SessionStorage在用户关闭页面后(会话结束)就会失效
4.Cookie 如何设置过期时间?如何删除 Cookie?
持久性Cookie:和关闭浏览器变失效的会话期Cookie不同,持久性Cookie可以指定一个特定时间(Expires)或有效期(Max-Age)
Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT;
-
设置cookie过期时间小于当前时间,那么就会删除该cookie
Set-Cookie: reg_fb_gate=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT
function deleteCookie(name) { document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:01 GMT;' }
在浏览器中删除存储的Cookie
5. Cache-Control: max-age=1000 缓存 与 ETag 的「缓存」有什么区别?
- Cache-Control: max-age =1000 是在这1000s内缓存有效,通过相同URL请求服务器时,浏览器在1000s不会发送HTTP请求访问服务器,而是从本地的内存和硬盘上拿到请求的资源。
- ETag:是通过校验两次请求资源的md5值是否改变来判断是否需要重新加载资源,是一定会发起HTTP请求且有响应,如果md5值相同,有请求有响应状态码304,但不会有响应的第四部分响应体;如果md5值不同,就会重新加载新的响应体。