ReactNative系列

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

2016-12-14  本文已影响50人  izhongxia

占位占位

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

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

一、教程

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

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

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

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

1. 强缓存 , 协商缓存

2. 既生Last-Modified何生Etag?

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

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

3. 浏览器行为

三、代码

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

//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 + '...')


上一篇 下一篇

猜你喜欢

热点阅读