初识Http缓存君

3,145 阅读5分钟

前言

二零一七年十一月十三日,就是我开始前端之旅的第n日,我独在卧室外徘徊,遇见程君,前来问我道,“你可曾为http缓存写了一点什么没有?”我说“没有”,他就正告我,“你还是写一点罢,http缓存应该很高兴与你相识,你们可以相互认识多一点”。

可是我实在无话可说。我只觉得所住的并非人间。产品经理不仁,以程序员为绉狗。可真的程序员,敢于直面惨淡的薪资,敢于正视淋漓的Bug。这是怎样的哀痛者和幸福者?然而重构又常常为庸人设计,以时间的流驶,来洗涤旧迹,仅使留下汹涌的加班和微漠的悲哀。在这汹涌的加班和微漠的悲哀中,又给人暂得偷生,维持着这似人非人的世界。我不知道这样的世界何时是一个尽头!

而我还在这样的世界里活着,于是觉得有写点什么的必要了。

缓存与性能优化息息相关,在知乎上,有一篇回答令我印象深刻大公司里怎样开发和部署前端代码? 该回答讲述了在部署阶段如何利用缓存提高性能,节约带宽。

一、相遇

与缓存君的相遇是在一场雪夜,当我看见她,我就知道我们会有故事,害羞的我不敢上前去与她交流。马克步是我的好朋友,本来不是的,自从我见到他在月下西瓜田里与猹不可描述后,我们便成了好朋友。他对我说“别怕,我来给你创造环境,你专心做自己的事情。但在此之前我先告诉关于缓存君的一点小知识”,我高兴极了。

  • 200 :正常的交流,每次你说的话都会在脑海里过一遍,并且找出合适礼貌的答语来回答你。
  • 304 :她知道你想要什么,但是需要大脑给她的身体一个指令,然后做出相应的动作给予你想要的。(协商缓存)
  • from memory cache或者disk cache :本垒打暗示,身体的本能反应,也是最快的。(强缓存)

二、交流

const http = require('http');
const fs = require('fs');
const path = require('path');
const server = http.createServer().listen(3000);

server.on('request',(req,res) => {
    const url = path.join(__dirname,'static',req.url);
    fs.readFile(url,(err,data) => {
        //马克步对我说,你别管其他的,每次有静态请求
        //就会执行这里的代码,读取文件然后返回出去。
        //之后会在这里设置响应头
        res.end(data);
    })    
});

然而在交流过程中却令我高兴不起来,她老是对我不冷不热的。


无论我和她对话多少次,她总是慢慢的考虑半天才回答我,这令我很伤心。于是马克步对我说,“别难过,我帮你设置一个暗号,每次你使用暗号与她交流的话,这会使你们的交流更愉快一些。暗号有两种哦”

//第一种 以资源内容hash为版本号
server.on('request',(req,res) => {
    const url = path.join(__dirname,'static',req.url);
    fs.readFile(url,(err,data) => {
        //如果之前的请求在响应头里返回了Etag 那么这次请求就可以拿到
        //req.headers['if-none-match'] == 之前响应头里的Etag
        if(req.headers['if-none-match'] == 'hello'){
            res.statusCode = 304;
            res.end();
        }else{
        //响应头里设置Etag,下次请求的时候,会在请求头里加上If-None-Match
            res.setHeader('Etag', 'hello');
            res.end(data);
        }
        res.end(data);
    })    
});

我再次和缓存君攀谈了起来。

这一次依然如同陌生人一样,但是这次我拿到了一个暗号,`Etag:hello`,我激动地赶紧使用暗号重复刚才的话。
这一次依然如同陌生人一样,但是这次我拿到了一个暗号,`Etag:hello`,我激动地赶紧使用暗号重复刚才的话。

呀,缓存君对我态度果然变了呀,而且速度也快了很多。
呀,缓存君对我态度果然变了呀,而且速度也快了很多。

//第二种 以资源修改时间为版本号
server.on('request',(req,res) => {
    const url = path.join(__dirname,'static',req.url);
    fs.readFile(url,(err,data) => {
        //如果之前的请求在响应头里返回了Last-Modifiedtag 那么这次请求就可以拿到
        //req.headers['if-modified-since'] == 之前响应头里的Last-Modified
        if(req.headers['if-modified-since']){
            res.statusCode = 304
            res.end()
        }else{    
            //在响应头里设置上次修改时间 必需为国际标准时间
            res.setHeader('Last-Modified', new Date().toUTCString());
            res.end(data);
        }
        res.end(data);
    })    
});

第二天再次攀谈,缓存君不认识我了。不过没关系,我拿到了时间暗号
第二天再次攀谈,缓存君不认识我了。不过没关系,我拿到了时间暗号

我们像老朋友一样愉快的交流了起来
我们像老朋友一样愉快的交流了起来

老姐、我想。。。

马克步最知我心思,他告诉我说,你若想要非常亲密的关系,其实设置一个分手时间就可以了。

server.on('request',(req,res) => {
    const url = path.join(__dirname,'static',req.url);
    fs.readFile(url,(err,data) => {
        //设置缓存过期时间
        res.setHeader('Cache-Control','max-age=5');
        res.end(data);
    })    
});

我怀着忐忑的心徐徐向前。

第一次交谈没什么变化,但是她给了我一个时间
第一次交谈没什么变化,但是她给了我一个时间

卧槽!瞬间就亲密无间了。
卧槽!瞬间就亲密无间了。

但是五秒后,又不认识我了(max-age以秒记)
但是五秒后,又不认识我了(max-age以秒记)

马克步心想:我寻思给你五秒钟应该够了呀!

此次经历

Http缓存按强势程度分为:

  • 强缓存 --- 有效期内,直接从本地获取资源,不需要发送请求
  • 弱缓存 --- 有效期内同上。在有效期外需要发送请求,如果返回304就继续用本地缓存,返回200则把新版本缓存起来,本地版本扔掉。

这次的经历实在是没什么营养。想要了解详细的话有如下建议:

  1. 大公司里怎样开发和部署前端代码?
  2. 使用 HTTP 缓存:Etag, Last-Modified 与 Cache-Control
  3. 浏览器缓存机制剖析
  4. MDN HTTP 缓存

最好能按照顺序阅读1、2、3,并且在阅读过程中辅以MDN文档。


其实马克步并不是他的真名,我曾经询问过他的真名,马克步说“我的名字实在是土的很,因为算命先生说我命中缺土,于是在名字中为我平衡”,我想了想马克步与猹的故事惊讶道:“难道你叫”,马克步说:“你想得不错,我叫闺垚