为了账号安全,请及时绑定邮箱和手机立即绑定

http缓存实战(让你再也不会学过就忘)

标签:
Node.js

“学过就忘”,一个知识点长时间不去读取,那么在你脑海中的基因片段会逐渐模糊,但是基因索引还是存在的。本篇文章通过实战理论想结合的方式来帮助大家更深刻的记忆常用知识点。 如有不足之处,恳请斧正。


什么是HTTP缓存 ?

http缓存通俗来说: 当客户端向服务器请求资源时,不会直接向服务器获取资源(喂:服务器,给我一张最新的自拍图片)。而是先看下自己的存储里有没有上次保存的还在有效期内的资源。如果有的话,就省下了一笔运费(流量)。这里举一个简单的例子:

  • 客户端需要a.js,于是发送一个请求头(1kb)

  • 服务端响应后,返回a.js(10kb) + 响应头(1kb)

  • 如此反复每次就是11kb的流量传送

但是我们我们需要的文件a.js的内容往往并没有发生变化,却仍然需要浪费流量,为了解决这个问题,于是人们提出了http缓存这个概念。

HTTP缓存可以分为强缓存和协商缓存。

强缓存

  • Expires

  • Cache-Control

  • Pragma

协商缓存

  • Last-Modified

  • If-Modified-Since

  • ETag

  • If-Not-Match

强缓存与协商缓存的区别:

用户大人:我现在需要a.js,你们帮我拿回来
强缓存:  稍等,我找下我这里有没有关于a.js的备份,找到了。(消耗0kb流量)
协商缓存: 我这里也有备份,不过我得问下服务端这个备份是不是最新款,发送请求头(1kb流量)。服务端回复(1kb流量)响应头则使用本地备份,若是返回a.js(10kb)和响用头(1kb)则使用服务器返回的最新数据。


强缓存

Expires

这是 HTTP 1.0 的字段,表示缓存到期时间,是一个绝对的时间 (当前时间 + 缓存时间)。在响应消息头中,请求资源前浏览器会用当前时间与其值对比,若是未过期则不需要再次请求。

新建cache.html

<!DOCTYPE html> <html lang="en"> <head>   <meta charset="UTF-8">   <meta name="viewport" content="width=device-width, initial-scale=1.0">   <link rel="icon" href="data:;base64,=">   <meta http-equiv="X-UA-Compatible" content="ie=edge">   <title>cache</title>   <script class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="cache.js"></script> </head> <body>   <h1>cache</h1> </body> </html> 复制代码

新建cache.js

let http = require('http'), fs = require('fs'), path = require('path'), url = require("url") http.createServer((req,res)=>{   let pathname = __dirname + url.parse(req.url).pathname; // 获取文件路径   let statusCode = 200 // 响应头状态码   let extname = path.extname(pathname) // 获取文件扩展名   let headType = 'text/html' // 内容类型   if( extname){     switch(extname){       case '.html':        headType = 'text/html'       break;       case '.js':         headType = 'text/javascript'       break;     }   }   fs.readFile(pathname, function (err, data) {     res.writeHead(statusCode, {       'Content-Type': headType,       'Expires':new Date(Date.now() + 10000).toUTCString() // 设置文件过期时间为10秒后     });     res.end(data);   }); }).listen(3000) console.log("Server running at http://127.0.0.1:3000/"); 复制代码

启动

node cache.js 复制代码

打开浏览器访问http://127.0.0.1:3000/cache.html 查看network


Cache-control

这是HTTP1.1的字段,这是一个相对时间'Cache-Control':'max-age=20'意思是20秒内使用缓存资源,不用请求服务器

// 省略其他代码   fs.readFile(pathname, function (err, data) {     res.writeHead(statusCode, {       'Content-Type': headType,       'Cache-Control':'max-age=20'     });


Cache-Control 除了max-age 相对过期时间以外,还有很多属性

   1. no-store:所有内容都不缓存
  2. no-cache:缓存,但是浏览器使用缓存前,都会请求服务器判断缓存资源是否是最新,它是个比较高贵的存在,因为它只用不过期的缓存。
  3. public 客户端和代理服务器(CDN)都可缓存
  4. private 只有客户端可以缓存

更多属性可参考 Cache-Control

Tips:也许大家在这里有一些小疑问,为什么对cache.html设置ExpiresCache-Control在谷歌浏览器里不生效。这时候查看request header 发现 Cache-Control: max-age=0,浏览器强制不用缓存。


这是因为浏览器会针对的用户不同行为采用不同的缓存策略,这样会导致在不同的浏览器会产生不同的现象:


Chrome does something quite different: 'Cache-Control' is always set to 'max-age=0′, no matter if you press enter, f5 or ctrl+f5. Except if you start Chrome and enter the url and press enter.

pragma

pragma是http/1.1之前版本的历史遗留字段,仅作为与http的向后兼容而定义。这里不做讨论。感兴趣的朋友可以点击了解 Pragma

node 热更新

这里如果大家觉得每次修改cache.js文件都需要重新执行node run cache.js,这里我们可以配置node 热更新

npm init npm i -D nodemon 复制代码

npm i -Dnpm install --save-dev的缩写

修改package.json

"scripts": {     "dev": "nodemon ./bin/www"   }, 复制代码

下面我们只需要执行一次npm run dev即可


对比缓存(协商缓存)

上面的强缓存依旧存在着很大的缺陷。当设置的时间过期后,不管文件内容有没有变化,我们不得不再次向服务器请求资源。这时候我们就需要用到协商缓存了。

Last-Modified

响应值,由服务器返回给客户端关于请求资源的最近修改时间 (GMT标准格式)

If-Modified-Since

请求值 , 由客户端发送给服务端上次返回的资源修改时间

首次请求时服务端会携带Last-Modified返回给客户端,客户端将其数值保存起来,并重新命名为If-Modified-Since 再次请求时,客户端会先发送一个携带If-Modified-Since的请求头发送到服务端,服务端会比较请求头的If-Modified-Since和服务器请求资源上次的修改时间(Last-Modified).

  1. 如果资源已经被修改:那么返回响应资源a.js(10kb) + 响应头(1kb),状态码:200 OK

  2. 如果没有被修改:那么只返回响应头(1kb),状态码:304 Not Modified

// 省略其他代码 let stat = fs.statSync(pathname);   fs.readFile(pathname, function (err, data) {     // 判断请求头的文件修改时间是否等于服务端的文件修改时间     if(req.headers['if-modified-since'] === stat.mtime.toUTCString()) { // mtime为文件内容改变的时间戳       statusCode = 304;     }     res.writeHead(statusCode, {       'Content-Type': headType,       'Last-Modified':stat.mtime.toUTCString()     });     res.end(data);       });




点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消