浅谈http中的Cache-Control

逃离Java 2020-10-18 14:25:38 ⋅ 987 阅读

前言

 

我们用http访问时,会先发送一个请求,之后服务器返回一个应答,在Chrome的开发者工具(按F12或右击选择检查)中展现了整个过程:
 
 
第一部分General是概要,包含请求地址,请求方式,状态码,服务器地址以及Referrer 策略。
 
第二部分是应答头部,是服务器返回的。
 
第三部分是请求头部,是客户端发送的。

 

这次我们从两个角度来看看http的缓存:缓存控制和缓存校验。
 
缓存控制:控制缓存的开关,用于标识请求或访问中是否开启了缓存,使用了哪种缓存方式。
 
缓存校验:如何校验缓存,比如怎么定义缓存的有效期,怎么确保缓存是最新的。

缓存控制

在http中,控制缓存开关的字段有两个:Pragma 和 Cache-Control。

Pragma

 

Pragma有两个字段Pragma和Expires。Pragma的值为no-cache时,表示禁用缓存,Expires的值是一个GMT时间,表示该缓存的有效时间。
 
Pragma是旧产物,已经逐步抛弃,有些网站为了向下兼容还保留了这两个字段。如果一个报文中同时出现Pragma和Cache-Control时,以Pragma为准。同时出现Cache-Control和Expires时,以Cache-Control为准。即优先级从高到低是 Pragma -> Cache-Control -> Expires

Cache-Control

在介绍之前,先啰嗦两个容易忽视的地方:
符合缓存策略时,服务器不会发送新的资源,但不是说客户端和服务器就没有会话了,客户端还是会发请求到服务器的。
Cache-Control除了在响应中使用,在请求中也可以使用。我们用开发者工具来模拟下请求时带上Cache-Control:勾选Disable cache,刷新页面,可以看到Request Headers中有个字段Cache-Control: no-cache。
 
 
同时在Response Headers中也能到Cache-Control字段,它的值是must-revalidate,这是服务端设置的。

Cache-Control字段

 

在请求中使用Cache-Control 时,它可选的值有:
 
 
在响应中使用Cache-Control 时,它可选的值有:
 
 
no-store优先级最高
 
在Cache-Control 中,这些值可以自由组合,多个值如果冲突时,也是有优先级的,而no-store优先级最高。我们可以测试下:在nginx中做如下配置:
server {
    listen 88;
    root /opt/ms;
    index index.php index.html index.htm index.nginx-debian.html;
   
    location ~* ^.+\.(css|js|txt|xml|swf|wav)$ {
        add_header Cache-Control no-store;
        add_header Cache-Control max-age=3600;
        add_header Cache-Control public;
        add_header Cache-Control only-if-cached;
        add_header Cache-Control no-cache;
        add_header Cache-Control must-revalidate;
    }
}
在/opt/ms下增加个文件type.css,内容如下:
a{
    color: #000000;
}
a:focus,a:hover {
    text-decoration: none;
    color: #708090;
}

 

配置好之后,reload下nginx,在浏览器访问地址http://127.0.0.1:88/type.css,可以看到响应头部包含nginx配置中的字段:
 
 
重复刷新访问,会发现每次的状态码都是200,原因是no-store的优先级最高,本地不保存,每次都需要服务器发送资源。

 

public和private的选择
 
如果你用了CDN,你需要关注下这个值。CDN厂商一般会要求cache-control的值为public,提升缓存命中率。如果你的缓存命中率很低,而访问量很大的话,可以看下是不是设置了private,no-cache这类的值。如果定义了max-age,可以不用再定义public,它们的意义是一样的。

哪里设置Cache-Control

以LNMP的环境为例,一次响应经历的过程是:php-cgi解析代码并执行,将结果返回给nginx,如果nginx前面有反向代理,则会经过一次反向代理服务器,所以cache-control可能会在nginx,php-cgi,php代码,反向代理服务器这些地方地方设置。在php.ini中,有个参数是session.cache_limiter,需要注意下。在nginx中有个很常见的配置:
location ~* ^.+\.(ico|gif|jpg|jpeg|png)$ {
            expires      30d;
        }
这个指令等同于cache-control: max-age=2592000,同时你会在响应头部看到一个etag字段,这是由于nginx默认开启,如果要关闭可以增加个配置etag off。这个etag就是我们接下要看的缓存校验字段。

缓存校验

在缓存中,我们需要一个机制来验证缓存是否有效。比如服务器的资源更新了,客户端需要及时刷新缓存;又或者客户端的资源过了有效期,但服务器上的资源还是旧的,此时并不需要重新发送。缓存校验就是用来解决这些问题的,在http 1.1 中,我们主要关注下Last-Modified 和 etag 这两个字段。

Last-Modified

 

服务端在返回资源时,会将该资源的最后更改时间通过Last-Modified字段返回给客户端。客户端下次请求时通过If-Modified-Since或者If-Unmodified-Since带上Last-Modified,服务端检查该时间是否与服务器的最后修改时间一致:如果一致,则返回304状态码,不返回资源;如果不一致则返回200和修改后的资源,并带上新的时间。
 
 
If-Modified-Since和If-Unmodified-Since的区别是:
 
If-Modified-Since:告诉服务器如果时间一致,返回状态码304
 
If-Unmodified-Since:告诉服务器如果时间不一致,返回状态码412

etag

 

单纯的以修改时间来判断还是有缺陷,比如文件的最后修改时间变了,但内容没变。对于这样的情况,我们可以使用etag来处理。
 
etag的方式是这样:服务器通过某个算法对资源进行计算,取得一串值(类似于文件的md5值),之后将该值通过etag返回给客户端,客户端下次请求时通过If-None-Match或If-Match带上该值,服务器对该值进行对比校验:如果一致则不要返回资源。
 
If-None-Match和If-Match的区别是:
 
If-None-Match:告诉服务器如果一致,返回状态码304,不一致则返回资源
 
If-Match:告诉服务器如果不一致,返回状态码412

总结

缓存开关是: pragma, cache-control。
缓存校验有:Expires,Last-Modified,etag。
从状态码的角度来看,它们的关系如下图:
 
cache-control的各个值关系如下图
 

参考资料

 

 

 

全部评论: 0

    我有话说:

    Redux中间件实践

    用户在UI层面触发行为,一个action对象通过store.dispatch派发到Reducer进行触发,接下来Reducer会根据type来更新对应Store上状态树,更改后state会触发

    DDDplus 1.0.2 发布,轻量级业务台开发框架

    DDDplus 简介 一套轻量级业务台开发框架,以DDD思想为本,致力于业务资产可沉淀可传承,全方位解决复杂业务场景扩展问题,实现台核心要素,赋能台建设。 融合了前台复杂生态协作方法论

    HTTP/2.0 服务器推送实现

    HTTP/2允许服务器在请求之前先推送响应信息到客户端(之前客户端有过请求),如果实现了HTTP缓存,推送响应信息可以在客户端被缓存(可通过no-cache进行配置)。

    Apache Traffic Control 5.1.2 发布,高可扩分布式 CDN 解决方案

    Apache Traffic Control 5.1.2 现已发布。Apache Traffic Control 是一个分布式、可扩展冗余解决方案,实现了现代 CDN 所有核心功能,可

    阿里大牛垃圾回收算法是如何设计

    前言 如果大家关注 JDK,会发现在频繁发布 JDK 版本,和垃圾回收相关 JEP (JDK Enhancement Proposals,Java 增强提案)越来越多了,垃圾回收

    smart-http 1.0.18 发布,轻量级国产 HTTP 服务器

    smart-http 是一款采用 Java 语言编写 Http 服务器,有别于业界知名 Web容器:Tomcat、Undertow,smart-http 并不支持 Servlet 规范,但对于

    Puma 5.2.1 发布,关注高并发 Ruby HTTP 服务器

    Puma 5.2.1 发布了。Puma 是一个简单、快速、线程化并且关注高并发 HTTP 1.1 服务器,适用于开发和生产 Ruby/Rack 应用。 本次更新内容包括: 修复 TCP

    Spring9种设计模式汇总

    Spring9种设计模式汇总

    「推荐」通过API网关实现微服务管控-限流,熔断和降级

      今天准备下基于API网关来实现微服务治理管控服务限流,熔断和降级方面内容。在前面微服务架构时候也到过类似通过Hystrix,Sentinel来是服务限流熔断。包括也不断

    移动Web实战篇-使用CSS Sprites减少你页面http请求

    用户新打开一个网页80%时间耗费在加载网页内容方面。很多炫酷网页往往通过图片来展现给用户,那么页面每加载一张图片就是一个http请求,如果图片过多会严重影响图片渲染速度。

    什么是微服务?什么是台?阿里台战略?

    微服务架构将单体应用,按照业务领域拆分为多个高内聚低耦合小型服务

    「轻阅读」推荐系统信息增强小技巧

    实用推荐系统构建经验,如何进行信息增强。

    「开源资讯」Guava 28.2 发布,Google Java 核心工具库

    前言 Guava 28.2 发布了,Guava 是 Google 一个开源项目,包含许多 Google 核心 Java 常用库,如:集合 [collections] 、缓存 [caching

    NodeJS 10.5.0 线程:实用介绍

    几天前,Node.js版本10.5.0发布,其中包含主要功能之一是添加了线程支持。

    微信小程序实战篇:如何解决https域名问题 ?

    开发自己微信小程序绕不开https问题,为了能在小程序调用我们自己API服务请打开看一看吧!!!

    Nodejs 搭建https服务器

    第一部分 搭建https服务器 前奏首先需要理解几个概念 HTTPS HTTP是一个网络协议,是专门用来传输 Web 内容; SSL(Secure Sockets Layer)缩写

    Gradle 6.7.1 发布,修复 6.7 严重错误

    这是 Gradle 6.7 修补版本,修复了 Gradle 6.7 几个严重错误,更新内容包括: 修复反向移植工具链错误问题 修复安装 Openjdk-11 后,Java 工具链在