浏览器发出一个请求,服务器解析出响应的结果返回给浏览器.

缓存是怎么工作的?

用户发起请求,浏览器检查本地是否存在缓存,如果第一次请求没有缓存,那就向服务器发起请求,服务器协商缓存的内容并且返回响应,接着返回缓存响应,再次请求时,会检查缓存是否失效,没有失效就使用本地缓存,如果本地缓存失效了,

缓存header

判断本地有没有失效的可以用

  • 返回时间Expires/Cache-Control

  Expires(比较老式):返回的是一个绝对时间,由于时区问题很少用

  Cache-Control(常用):返回的是一个相对时间

  • 修改时间Last-Modified/If-Modified_Since

  Last-Modified:向服务器校验的时候拿到的结果,每次返回响应的时候会告诉Last-Modified时间

  If-Modified_Since:浏览器第二次或者第三次发起请求时,会把上次的修改时间放在修改头的If-Modified_Since

  • 服务器校验 If-None-Match /TRag

defaultConfig.js

module.exports={
root:process.cwd(),
hostname:'127.0.0.1',
port:9527,
compress:/\.(html|js|css|md)/,
cache:{
maxAge:600,
expire:true,
cacheControl:true,
lastModified:true,
etag:true
}
}

新建文件src/helper/cache.js

const {cache} = require('../config/defaultConfig')
// 更新一下响应,修改时间
function refreshRes(stats,res){
const {maxAge,expires,cacheControl,lastModified,etag} = cache; if(expires){
res.setHeader('Expires',(new Date(Date.now() + maxAge *1000)).toUTCString())
}
if(cacheControl){
res.setHeader('Cache-Control',`public,max-age=${maxAge}`)
}
if(lastModified){
res.setHeader('Last-Modified',stats.mtime.toUTCString())
}
if(etag){
res.setHeader('ETag',`${stats.size} = ${stats.mtime}`);
} } module.exports = function isFresh(stats,req,res){
refreshRes(stats,res)
const lastModified = req.headers['if-modified-since']
const etag = req.headers['if-none-match']
if(!lastModified && !etag){
return false
}
if(lastModified && lastModified !==res.getHeader('Last-Modified')) {
return false
}
if(etag && etag !== res.getHeader('Etag')){
return false
}
return true
}

route.js引用ca'ch

const fs =require('fs')
const path = require('path')
const Handlebars = require('handlebars')
const promisify = require('util').promisify;
const stat = promisify(fs.stat)
const readdir = promisify(fs.readdir);
// //引用range范围
// const range = require('./range')
const config = require('../config/defaultConfig')
const tplPath = path.join(__dirname,'../template/dir.tpl')
const source = fs.readFileSync(tplPath);
const template = Handlebars.compile(source.toString())
//引入新加的mime,对contentType的判断
const mime = require('./mime')
const compress = require('./compress') //引用range范围
const range = require('./range') // 引入cache
const isFresh = require('./cache') module.exports=async function(req,res,filePath){
try{
const stats =await stat(filePath)
if(stats.isFile()){
const contentType = mime(filePath)
res.statusCode = 200
res.setHeader('content-Type',contentType) if(isFresh(stats,req,res)){
res.statusCode = 304;
res.end()
return
} let rs;
const {code,start,end} = range(stats.size, req, res)
if(code === 200){
res.statusCode = 200
rs = fs.createReadStream(filePath)
}else{
res.statusCode = 216 //测试随便定
rs = fs.createReadStream(filePath,{start,end})
} // let rs = fs.createReadStream(filePath)
if(filePath.match(config.compress)){
rs = compress(rs,req,res)
}
rs.pipe(res);
// fs.readFile(filePath,(err,data)=>{
// res.end(data)
// });
}else if(stats.isDirectory()){
//所有异步调用必须用await
const files =await readdir(filePath);
res.statusCode = 200
res.setHeader('content-Type','text/html')
const dir = path.relative(config.root,filePath)
const data = {
title:path.basename(filePath),
// dir:config.root,
dir:dir?`/${dir}`:'',
files:files.map(file=>{
return {
file,
icon:mime(file)
}
})
}
res.end(template(data));
}
}catch(ex){
console.error(ex);
res.statusCode = 404
res.setHeader('content-Type','text/plain')
res.end(`${filePath} is not a directory or file\n ${ex.error}`)
}
}

主要代码是

运行结果

首次

刷新

NodeJS4-7静态资源服务器实战_缓存的更多相关文章

  1. NodeJS4-8静态资源服务器实战_构建cli工具

    Cli(command-line interface),中文是 命令行界面,简单来说就是可以通过命令行快速生成自己的项目模板等功能(比较熟悉的是vue-cli脚手架这些),把上述写的包做成Cli工具. ...

  2. NodeJS4-5静态资源服务器实战_优化压缩文件

    浏览器控制台看一下RequestHeader有一个Accept-Encoding,而RespondHeaders中也会有一个Content-Encoding和他进行对应. Accept-Encodin ...

  3. NodeJS4-9静态资源服务器实战_发到npm上

    登录->publish一下 ->上npm官网查看 -> 安装全局 //登录 npm login //推上去npm npm publish //全局安装 npm i -g 你的文件名

  4. NodeJS4-4静态资源服务器实战_优化引入模板引擎

    引入模板引擎(handlebars) cnpm i handlebars 结构大概是这样子的,新建模板dir.tpl文件和route.js dir.tpl <!DOCTYPE html> ...

  5. NodeJS4-3静态资源服务器实战_优化成近似同步写法

    实例3 上面有点回调,优化成近似同步的写法 route.js const fs =require('fs') const promisify = require('util').promisify; ...

  6. NodeJS4-2静态资源服务器实战_实现获取文件路径

    实例2 : 实现获取文件路径,判断是文件还是文件夹,如果是文件夹就显示里面的列表文件,如果是文件就显示里面的内容 defaultConfig.js module.exports={ root:proc ...

  7. NodeJS4-1静态资源服务器实战_实现访问获取里面的内容

    .gitignore 匹配模式前 / 代表项目根目录 匹配模式最后加 / 代表是目录 匹配模式前加 ! 代表取反 * 代表任意一个字符 ? 匹配任意一个字符 ** 匹配多级目录 统一代码风格配置可以用 ...

  8. NodeJS4-6静态资源服务器实战_range范围请求

    range范围请求:向服务器发起请求可以申明我想请求判断内容的范围,从多少个字节到多少个字节,一次要求把所有的内容拿回来,服务器在得到相应的请求之后,从拿到对应的文件,拿到对应的字节返回给客户端.要实 ...

  9. 【原创】分布式之缓存击穿 【原创】自己动手实现静态资源服务器 【原创】自己动手实现JDK动态代理

    [原创]分布式之缓存击穿   什么是缓存击穿 在谈论缓存击穿之前,我们先来回忆下从缓存中加载数据的逻辑,如下图所示 因此,如果黑客每次故意查询一个在缓存内必然不存在的数据,导致每次请求都要去存储层去查 ...

随机推荐

  1. .NET做人脸识别并分类

    .NET做人脸识别并分类 在游乐场.玻璃天桥.滑雪场等娱乐场所,经常能看到有摄影师在拍照片,令这些经营者发愁的一件事就是照片太多了,客户在成千上万张照片中找到自己可不是件容易的事.在一次游玩等活动或家 ...

  2. Flex容器拖动(Bordercontainer为例)

    Bordercontainer的拖放到任意位置. mxml: 为Bordercontainer添加鼠标按下和弹起事件 <s:BorderContainer id="bdShow&quo ...

  3. leetcode 114二叉树转换成链表

    解法一 可以发现展开的顺序其实就是二叉树的先序遍历.算法和 94 题中序遍历的 Morris 算法有些神似,我们需要两步完成这道题. 将左子树插入到右子树的地方 将原来的右子树接到左子树的最右边节点 ...

  4. .NET Core应用框架AA介绍(二)

    AA的开源地址 https://github.com/ChengLab/AAFrameWork AA框架是一个基础应用框架,是建立在众多大家熟知的流行工具之上并与之集成.比如:ASP.NET Core ...

  5. 从别人那里拿过来的工程,在Idea上打开时报错

    如果是这个错误:也许原因有很多种,但是不妨试一下⑴将给你项目工程的人的.idea文件夹删除,这样在你导入工程时,会生成一个属于你本地的.idea.⑵最好是使用SVN重新把项目工程检出(把项目下载下来, ...

  6. Idea创建maven项目,报错xxx already exists in VFS

    1.问题描述: 我打算在父级maven项目中创建子级project,但是一直报错如下: 2.stackover flow中找到了问题的答案, 地址:https://stackoverflow.com/ ...

  7. CCNA 之 十三 广域网概述

    广域网概述 为什么需要WAN ? 分区或分支机构的员工需要与总部通信并共享数据: 组织经常需要与其他组织远距离共享信息: 经常出差的员工需要访问公司网络信息: 什么事广域网链路? 用于连接LAN的.跨 ...

  8. 行内元素(inline标签)设置了行高为什么不生效,还是表现为父盒子的行高?行内元素行高问题终极解释

    最近在看张鑫旭大佬的<css世界>,读到5.2.4  内联元素 line-height 的“大值特性” ,产生了疑惑, 在开发中确实也遇到了同样的问题,深入探究后得出结果,先说结论吧,论证 ...

  9. fsockopen用feof读取http响应内容的一些问题

    在前面三个例子中,都有这么一段代码: while (!feof($fp)) { // 读取文件/数据 //$content .= fgets($fp, 128); //$line = fread($f ...

  10. Netty学习——通过websocket编程实现基于长连接的双攻的通信

    Netty学习(一)基于长连接的双攻的通信,通过websocket编程实现 效果图,客户端和服务器端建立起长连接,客户端发送请求,服务器端响应 但是目前缺少心跳,如果两个建立起来的连接,一个断网之后, ...