【HTTP缓存】一步一步打造自己的静态web服务器

占位占位

时间:2016-12-12 23:01:08
学习了理论的知识,还是需要实践来加深对HTTP缓存的理解。 【这里占个位置,告诉自己要去实践一下】

更新时间:2016-12-14 15:04:34

一、教程

  1. 《用NodeJs打造你的静态文件服务器》

【推荐】根据教程一步一步敲出来,大大加深了对缓存的理解,也知道实际中该如何使用。

二、采用技术以及缓存应用学习

采用NodeJs的 http,url,fs,path,zlib 实现一个简单的web服务器,支持强缓存,协商缓存,GZip压缩。

1. 强缓存 , 协商缓存

  • 强缓存主要是通过设置 Response 的Expires 和 Cache-Control`

  • 协商缓存主要是设置Response 返回 Last-Modified, 浏览器请求资源的时候,会把这个值放在 If-Modified-Since 的Header里面,然后这里判断是否过时了。

  • 协商缓存还有一个ETag可以配置使用,但是ETag需要这里生成唯一的资源标识,然后返回给浏览器,浏览器再次请求一个资源的时候,会带上这个ETag标记,放在 Request的 If-None-Match 的 header字段,如果文件没有被修改,则返回304 ,浏览器采用本地缓存。

2. 既生Last-Modified何生Etag?

你可能会觉得使用Last-Modified已经足以让浏览器知道本地的缓存副本是否足够新,为什么还需要Etag(实体标识)呢?HTTP1.1中Etag的出现主要是为了解决几个Last-Modified比较难解决的问题:

  • Last-Modified标注的最后修改只能精确到秒级,如果某些文件在1秒钟以内,被修改多次的话,它将不能准确标注文件的修改时间

  • 如果某些文件会被定期生成,当有时内容并没有任何变化,但Last-Modified却改变了,导致文件没法使用缓存

  • 有可能存在服务器没有准确获取文件修改时间,或者与代理服务器时间不一致等情形

Etag是服务器自动生成或者由开发者生成的对应资源在服务器端的唯一标识符,能够更加准确的控制缓存。Last-Modified与ETag是可以一起使用的,服务器会优先验证ETag,一致的情况下,才会继续比对Last-Modified,最后才决定是否返回304。

3. 浏览器行为

  • 在按CMD+R刷新浏览器的时候,一直没有看到使用缓存,莫名其妙的,后面发现是 按刷新的时候,跳过了强缓存,协商缓存会验证。
  • CTRL+CMD+R 跳过 强缓存 和 协商缓存
  • 只有浏览器地址栏,输入地址,或者页面超链接跳转,采用使用强缓存验证

三、代码

根据教程一步一步自己敲出来更好。

//config.js
exports.Expires = {
  fileMatch: /^(gif|png|jpg|js|css)$/ig,
  maxAge: 60 * 60 * 24 * 365
}
exports.Compress = {
  match: /css|js|html/ig
}

//MIME.js
// Header 的  Content-Type 
exports.types = {
  "css": "text/css",
  "gif": "image/gif",
  "html": "text/html",
  "ico": "image/x-icon",
  "jpeg": "image/jpeg",
  "jpg": "image/jpeg",
  "js": "text/javascript",
  "json": "application/json",
  "pdf": "application/pdf",
  "png": "image/png",
  "svg": "image/svg+xml",
  "swf": "application/x-shockwave-flash",
  "tiff": "image/tiff",
  "txt": "text/plain",
  "wav": "audio/x-wav",
  "wma": "audio/x-ms-wma",
  "wmv": "video/x-ms-wmv",
  "xml": "text/xml"
};
//index.js
var PORT = 9999
var http = require('http')
var url = require('url')
var fs = require('fs')
var path = require('path')
var zlib = require("zlib")

var MIME = require('./MIME.js').types
var config = require('./config.js')

var server = http.createServer(function (request, response) {
  // 获取资源路径
  var pathname = url.parse(request.url).pathname
  var realPath = 'assets' + pathname

  fs.exists(realPath, function (exists) {
    if (!exists) {
      response.writeHead(404, { 'Content-Type': 'text/plain' })
      response.write('This Request Url ' + pathname + ' was not found on this server')
      response.end()
    } else {
      fs.readFile(realPath, 'binary', function (err, file) {
        if (err) {
          response.writeHead(500, { 'Content-Type': 'text/plain' })
          response.end(err.Error)
        } else {
          var ext = path.extname(realPath)
          ext = ext ? ext.slice(1) : 'unknown'
          var contentType = MIME[ext] || 'text/plain'

          //设置强缓存 Expires   Cache-Control
          var expires = new Date()
          expires.setTime(expires.getTime() + config.Expires.maxAge * 1000)
          response.setHeader('Expires', expires.toUTCString())
          response.setHeader('Cache-Control', 'max-age=' + config.Expires.maxAge)


          //设置协商缓存  Last-Modified   If-Modified-Since   Tag  If-None-Match
          fs.stat(realPath, function (err, stat) {
            var lastModified = stat.mtime.toUTCString()
            response.setHeader("Last-Modified", lastModified)
            if (request.headers["If-Modified-Since"] && lastModified == request.headers["If-Modified-Since"]) {
              response.writeHead(304, "Not Modified")
              response.end()
            } else {

              //使用GZIP压缩资源   利用Node的 zlib 压缩
              var raw = fs.createReadStream(realPath)
              var acceptEncoding = request.headers['accept-encoding'] || ""
              var matched = ext.match(config.Compress.match)

              if (matched && acceptEncoding.match(/\bgzip\b/)) {
                response.writeHead(200, "Ok", { 'Content-Encoding': 'gzip' });
                raw.pipe(zlib.createGzip()).pipe(response);
              } else if (matched && acceptEncoding.match(/\bdeflate\b/)) {
                response.writeHead(200, "Ok", { 'Content-Encoding': 'deflate' });
                raw.pipe(zlib.createDeflate()).pipe(response);
              } else {
                response.writeHead(200, { 'Content-Type': contentType })
                raw.pipe(response);
              }
            }
          })
          console.log('load assets file:' + realPath)
        }
      })
    }
  })
})

server.listen(PORT)

console.log('Server runing at port:' + PORT + '...')


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容