There are only two hard things in Computer Science: cache invalidation and naming things.

-- Phil Karlton

通过Internet获取资源既缓慢,成本又高。为此,Http协议里包含了控制缓存的部分,以使Http客户端可以缓存和重用以前获取的资源,从而优化性能,提升体验。虽然Http中关于缓存控制的部分,随着协议演进,有一些变化。但我觉着,作为后端程序员,在开发Web服务时,只需要关注请求头If-None-Match、响应头ETag、响应头Cache-Control就足够了。因为这三个Http头就可以满足你的需求,并且,当今绝大多数的浏览器,都支持这三个Http头。我们所要做的就是,确保每个服务器响应都提供正确的 HTTP 头指令,以指导浏览器何时可以缓存响应以及可以缓存多久。

缓存在哪儿?

上图中有三个角色,浏览器、Web代理和服务器,如图所示Http缓存存在于浏览器和Web代理中。当然在服务器内部,也存在着各种缓存,但这已经不是本文要讨论的Http缓存了。所谓的Http缓存控制,就是一种约定,通过设置不同的响应头Cache-Control来控制浏览器和Web代理对缓存的使用策略,通过设置请求头If-None-Match和响应头ETag,来对缓存的有效性进行验证。

响应头ETag

ETag全称Entity Tag,用来标识一个资源。在具体的实现中,ETag可以是资源的hash值,也可以是一个内部维护的版本号。但不管怎样,ETag应该能反映出资源内容的变化,这是Http缓存可以正常工作的基础。

如上例中所展示的,服务器在返回响应时,通常会在Http头中包含一些关于响应的元数据信息,其中,ETag就是其中一个,本例中返回了值为x1323ddx的ETag。当资源/file的内容发生变化时,服务器应当返回不同的ETag。

请求头If-None-Match

对于同一个资源,比如上一例中的/file,在进行了一次请求之后,浏览器就已经有了/file的一个版本的内容,和这个版本的ETag,当下次用户再需要这个资源,浏览器再次向服务器请求的时候,可以利用请求头If-None-Match来告诉服务器自己已经有个ETag为x1323ddx的/file,这样,如果服务器上的/file没有变化,也就是说服务器上的/file的ETag也是x1323ddx的话,服务器就不会再返回/file的内容,而是返回一个304的响应,告诉浏览器该资源没有变化,缓存有效。

如上例中所示,在使用了If-None-Match之后,服务器只需要很小的响应就可以达到相同的结果,从而优化了性能。

响应头Cache-Control

每个资源都可以通过Http头Cache-Control来定义自己的缓存策略,Cache-Control控制谁在什么条件下可以缓存响应以及可以缓存多久。 最快的请求是不必与服务器进行通信的请求:通过响应的本地副本,我们可以避免所有的网络延迟以及数据传输的数据成本。为此,HTTP 规范允许服务器返回一系列不同的 Cache-Control 指令,控制浏览器或者其他中继缓存如何缓存某个响应以及缓存多长时间。

Cache-Control 头在 HTTP/1.1 规范中定义,取代了之前用来定义响应缓存策略的头(例如 Expires)。当前的所有浏览器都支持 Cache-Control,因此,使用它就够了。

以下我来介绍可以再Cache-Control中设置的常用指令。

max-age

该指令指定从当前请求开始,允许获取的响应被重用的最长时间(单位为秒。例如:Cache-Control:max-age=60表示响应可以再缓存和重用 60 秒。需要注意的是,在max-age指定的时间之内,浏览器不会向服务器发送任何请求,包括验证缓存是否有效的请求,也就是说,如果在这段时间之内,服务器上的资源发生了变化,那么浏览器将不能得到通知,而使用老版本的资源。所以在设置缓存时间的长度时,需要慎重。

public和private

如果设置了public,表示该响应可以再浏览器或者任何中继的Web代理中缓存,public是默认值,即Cache-Control:max-age=60等同于Cache-Control:public, max-age=60。

在服务器设置了private比如Cache-Control:private, max-age=60的情况下,表示只有用户的浏览器可以缓存private响应,不允许任何中继Web代理对其进行缓存 - 例如,用户浏览器可以缓存包含用户私人信息的 HTML 网页,但是 CDN 不能缓存。

no-cache

如果服务器在响应中设置了no-cache即Cache-Control:no-cache,那么浏览器在使用缓存的资源之前,必须先与服务器确认返回的响应是否被更改,如果资源未被更改,可以避免下载。这个验证之前的响应是否被修改,就是通过上面介绍的请求头If-None-match和响应头ETag来实现的。

需要注意的是,no-cache这个名字有一点误导。设置了no-cache之后,并不是说浏览器就不再缓存数据,只是浏览器在使用缓存数据时,需要先确认一下数据是否还跟服务器保持一致。如果设置了no-cache,而ETag的实现没有反应出资源的变化,那就会导致浏览器的缓存数据一直得不到更新的情况。

no-store

如果服务器在响应中设置了no-store即Cache-Control:no-store,那么浏览器和任何中继的Web代理,都不会存储这次相应的数据。当下次请求该资源时,浏览器只能重新请求服务器,重新从服务器读取资源。

怎样决定一个资源的Cache-Control策略呢?

下面这个流程图,可以帮到你。

Reference

https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching?hl=zh-cn

写给后端程序员的HTTP缓存原理介绍的更多相关文章

  1. 写给后端程序员的HTTP缓存原理介绍--怎样决定一个资源的Cache-Control策略呢

    通过Internet获取资源既缓慢,成本又高.为此,Http协议里包含了控制缓存的部分,以使Http客户端可以缓存和重用以前获 取的资源,从而优化性能,提升体验.虽然Http中关于缓存控制的部分,随着 ...

  2. 科普,想成为厉害的 Java 后端程序员,你需要懂这 13 个知识点

    老读者就请肆无忌惮地点赞吧,微信搜索[沉默王二]关注这个在九朝古都洛阳苟且偷生的程序员.本文 GitHub github.com/itwanger 已收录,里面还有我精心为你准备的一线大厂面试题. 站 ...

  3. 科普,想成为厉害的 Java 后端程序员,你需要懂这些

    站在运筹帷幄的角度来看,一名厉害的 Java 后端程序员都需要懂得哪些知识呢?我想,这也是很多读者迫切想知道的一个问题,因为如果不站在一个宏观的角度的话,所有学过的知识点都是零散的,就感觉像一只迷路的 ...

  4. 后台程序员的HTTP缓存

    1.后端程序员只需要关注请求头: if-None-Match //上一次response头中的ETag的值. 响应头: Etag //是URL的Entity Tag,用于标示URL对象是否改变,区分不 ...

  5. 后端程序员必备的 Linux 基础知识

    1. 从认识操作系统开始 正式开始 Linux 之前,简单花一点点篇幅科普一下操作系统相关的内容. 1.1. 操作系统简介 我通过以下四点介绍什么是操作系统: 操作系统(Operating Syste ...

  6. Angular学习资料大全和常用语法汇总(让后端程序员轻松上手)

    前言: 首先为什么要写这样的一篇文章呢?主要是因为前段时间写过一些关于Angualr的相关实战文章,有些爱学习的小伙伴对这方面比较感兴趣,但是又不知道该怎么入手(因为认识我的大多数小伙伴都是后端的同学 ...

  7. 敏捷软件开发:原则、模式与实践——第13章 写给C#程序员的UML概述

    第13章 写给C#程序员的UML概述 UML包含3类主要的图示.静态图(static diagram)描述了类.对象.数据结构以及它们之间的关系,藉此表现出了软件元素间那些不变的逻辑结构.动态图(dy ...

  8. 写给嵌入式程序员的循环冗余校验(CRC)算法入门引导

    写给嵌入式程序员的循环冗余校验(CRC)算法入门引导 http://blog.csdn.net/liyuanbhu/article/details/7882789 前言 CRC校验(循环冗余校验)是数 ...

  9. 不写注释的程序员-Models

    Models 不写注释的程序员-Models # This is an auto-generated Django model module. # You'll have to do the foll ...

随机推荐

  1. vue.js的基本操作

    1.{{message}}输出data数据中的message. 2.v-for="todo in todos"输出data数据中的dotos数组 3.v-on:click=&quo ...

  2. python Django session/cookie

    一, Cookie #cookie # def cook1(request): # print(request.COOKIES) # 查看cooke # # print(request.get_sig ...

  3. 开源免费的HTML5游戏引擎

    青瓷引擎的成长 青瓷引擎自2015年4月项目启动开始,7月首次亮相2015年ChinaJoy,便得到业界的极大关注,随后开启限量测试,收到数百个开发者团队的试用申请及反馈,期间经历了18个内测版本,完 ...

  4. WIM镜像添加多语言支持

    起初的想法: intel 600p虽然速度一般,但pcie还是值得一试的.购买后发现原来的win7版本无法识别就找了KB2990941和KB3087873两个补丁,成功识别出了硬盘.期间通过dezor ...

  5. C/C++_date&time

    在标准C/C++中与日期和时间相关的数据结构 注意:年份是实际年份与  1900  的差值 我们可通过tm结构来获得日期和时间,tm结构在time.h中的定义如下: #ifndef _TM_DEFIN ...

  6. C# Just want 入门

    1. 终于明白为什么以前的程序在结尾部分会经常出现 input any key to exit! using System; namespace ConsoleApplication1 { class ...

  7. SQL Server2000清除数据库日志

    sqlserver2000压缩日志 可以将jb51.ldf文件变得很小,方便备份数据库等,在sqlserver查询分析器中执行即可.复制代码 代码如下: DUMP TRANSACTION [jb51] ...

  8. 初探SQL注入

    1.1注入语句(通过时间注入函数) 数据库名称 localhost:8080/ScriptTest/userServlet?username='union SELECT IF(SUBSTRING(cu ...

  9. "SQL Server does not handle comparison of NText, Text, Xml, or Image data types."

    "SQL Server does not handle comparison of NText, Text, Xml, or Image data types." sql2000 ...

  10. SSH学习笔记

    Struts2登录模块处理流程: 浏览器发送请求http://localhost/appname/login.action,到web应用服务器: 容器接收到该请求,根据web.xml的配置,服务器将请 ...