{"id":22180480,"url":"https://github.com/levelopers/notes-web-cache","last_synced_at":"2026-01-06T11:07:49.069Z","repository":{"id":63903901,"uuid":"571683242","full_name":"levelopers/notes-web-cache","owner":"levelopers","description":null,"archived":false,"fork":false,"pushed_at":"2022-12-06T15:38:09.000Z","size":10,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-01-29T23:29:46.206Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/levelopers.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-11-28T16:56:47.000Z","updated_at":"2022-11-28T16:56:47.000Z","dependencies_parsed_at":"2023-01-23T11:31:19.129Z","dependency_job_id":null,"html_url":"https://github.com/levelopers/notes-web-cache","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/levelopers%2Fnotes-web-cache","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/levelopers%2Fnotes-web-cache/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/levelopers%2Fnotes-web-cache/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/levelopers%2Fnotes-web-cache/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/levelopers","download_url":"https://codeload.github.com/levelopers/notes-web-cache/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245331884,"owners_count":20598060,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-02T09:18:24.171Z","updated_at":"2026-01-06T11:07:44.036Z","avatar_url":"https://github.com/levelopers.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"## Web缓存\r\n\r\n\r\n### http缓存\r\n\r\n1. 使用缓存优点:\r\n\r\n- 缓存 减少了冗余的数据传输，节省了你的网络费用。（避免服务器重复传输同一份文档，缓存可以保留服务器响应副本，后继请求可以由缓存的副本来应对）\r\n- 缓存 缓解了网络瓶颈的问题。不需要更多的带宽就能够更快地加载页面。（在本地网络的快速以太网加入缓存服务器，解决长距离低带宽网络带来的高延迟问题）\r\n- 缓存 降低了对原始服务器的要求。服务器可以更快地响应，避免过载的出现。（在瞬间拥塞时，减轻服务器压力）\r\n- 缓存 降低了距离时延，因为从较远的地方加载页面会更慢一些。（远距离传输的时延受光速自身和网络路由器等因素影响）\r\n\r\n总结：提高性能降低费用\r\n\r\n2. http缓存处理流程\r\n\r\n2.1 缓存命中\r\n`缓存命中（cache hit）`：可以用已有的副本为某些到达缓存的请求提供服务\r\n`缓存未命中（cache miss）`：到达缓存的请求没有副本可用，而被转发给原始服务器\r\n\r\n\u003cimage src=\"https://user-images.githubusercontent.com/38830527/204339115-b31857b7-3e06-4dca-883b-07651e0ff61d.png\" alt=\"http缓存处理流程\" style=\"width:300px;\" /\u003e\r\n\r\n2.2 新鲜度检测\r\n原始服务器的内容可能会发生变化，缓存要不时对其进行检测，看看它们保存的副本是否仍是服务器上最新的副本。这些“新鲜度检测”被称为`HTTP再验证（revalidation）`\r\n\r\n\r\n2.3 缓存命中率\r\n`文档命中率（document hit rate）`:由缓存提供服务的请求所占的比例被称为缓存命中率（cache hit rate，或称为缓存命中比例）。对现在中等规模的Web缓存来说，40%的命中率是很合理的。提高文档命中率对降低整体延迟（时延）很有好处。\r\n\r\n`字节命中率`表示的是缓存提供的字节在传输的所有字节中所占的比例。通过这种度量方式，可以得知节省流量的程度。100%的字节命中率说明每个字节都来自缓存，没有流量流到因特网上去。提高文档命中率对降低整体延迟（时延）很有好处\r\n\r\n3. 缓存的拓扑结构\r\n\r\n`私有缓存（private cache）`：是单个用户专用的，包含了单个用户最常用的页面。Web浏览器中有内建的私有缓存——大多数浏览器都会将常用文档缓存在你个人电脑的磁盘和内存中.\r\n`公有缓存（public cache）`：是共享的缓存,包含了某个用户团体的常用页面。公有缓存是特殊的共享代理服务器，被称为缓存代理服务器（caching proxy server），或者更常见地被称为代理缓存（proxy cache）。共享的副本为所有的请求服务，以降低网络流量。\r\n\r\n缓存的拓扑结构：\r\n\u003cimage src=\"https://user-images.githubusercontent.com/38830527/204339960-23ccbe1b-baef-477d-b08b-818e3cda3cf7.png\" alt=\"缓存的拓扑结构\" style=\"width:300px;\"/\u003e\r\n\r\n在缓存层次结构很深的情况下，请求可能要穿过很长一溜缓存，但每个拦截代理都会添加一些性能损耗，当代理链路变得很长的时候，这种性能损耗会变得非常明显。\r\n\r\n4. 缓存的处理步骤\r\n\r\n(1) 接收——缓存从网络中读取抵达的请求报文。\r\n(2) 解析——缓存对报文进行解析，提取出URL和各种首部。\r\n(3) 查询——缓存查看是否有本地副本可用，如果没有，就获取一份副本（并将其保存在本地）。已缓存对象中包含了服务器响应主体和原始服务器响应首部还包含了一些元数据（metadata），用来记录对象在缓存中停留了多长时间，以及它被用过多少次等。\r\n(4) 新鲜度检测——缓存查看已缓存副本是否足够新鲜，如果不是，就询问服务器是否有任何更新。\r\n(5) 创建响应——缓存会用新的首部和已缓存的主体来构建一条响应报文。已缓存的服务器响应首部进行改造或插入新鲜度信息（Cache-Control、Age以及Expires首部）\r\n(6) 发送——缓存通过网络将响应发回给客户端。\r\n(7) 日志——缓存可选地创建一个日志文件条目来描述这个事务。\r\n\r\n缓存处理步骤：\r\n\u003cimage src=\"https://user-images.githubusercontent.com/38830527/204340180-528ad399-ff25-4b2d-829c-b0f38b5bd6e7.png\" alt=\"缓存处理步骤\" style=\"width:300px;\"/\u003e\r\n\r\n缓存请求流程图：\r\n\u003cimage src=\"https://user-images.githubusercontent.com/38830527/204340269-f61359a0-71b2-47bb-be06-0c21b4e964c5.png\" alt=\"缓存请求流程图\" style=\"width:300px;\"/\u003e\r\n\r\n5. 新鲜度检测\r\n\r\n5.1 Expires首部和Cache-Control:max-age首部 （强缓存）\r\n不需要发送请求到服务端，直接读取浏览器本地缓存\r\n\r\n- `Cache-Control` 通用消息头字段，被用于在 http 请求和响应中，通过指定指令来实现缓存机制。\r\n\r\n```\r\n常用指令：\r\n1. no-store\r\n缓存不应存储有关客户端请求或服务器响应的任何内容，即不使用任何缓存。\r\n2. max-age=\u003cseconds\u003e\r\n设置缓存存储的最大周期，超过这个时间缓存被认为过期 (单位秒)。与Expires相反，时间是相对于请求的时间。\r\n3. no-cache\r\n在发布缓存副本之前，强制要求缓存把请求提交给原始服务器进行验证 (协商缓存验证)。相当于 max-age=0, must-revalidate，综合起来的效果是，本地缓存每次使用前都必须经过服务端校验。\r\n4. must-revalidate\r\n一旦资源过期（比如已经超过max-age），在成功向原始服务器验证之前，缓存不能用该资源响应后续请求。\r\n```\r\n\r\n5.2 服务器再验证（协商缓存）\r\n当已缓存文档过期“不新鲜”了，缓存需要询问原始服务器文档是否发生了变化。再验证流程如下：\r\n\r\n- 如果再验证显示内容 发生了变化，缓存会获取一份新的文档副本，并将其存储在旧文档的位置上，然后将文档发送给客户端。\r\n- 如果再验证显示内容 没有发生变化，缓存只需要获取新的首部，包括一个新的过期日期，并对缓存中的首部进行更新就行了。\r\n\r\n5.3 条件式时间维度再验证\r\n\r\n- `If-Modified-Since`是一个条件式请求首部，服务器只在所请求的资源在给定的日期时间之后对内容进行过修改的情况下才会将资源返回，状态码为 200 。如果请求的资源从那时起未经修改，那么返回一个不带有消息主体的 304 响应，而在 `Last-Modified `首部中会带有上次修改时间。\r\n```\r\nIf-Modified-Since: \u003cday-name\u003e, \u003cday\u003e \u003cmonth\u003e \u003cyear\u003e \u003chour\u003e:\u003cminute\u003e:\u003csecond\u003e GMT\r\n```\r\n- `Last-Modified`是一个响应首部，其中包含源头服务器认定的资源做出修改的日期及时间。它通常被用作一个验证器来判断接收到的或者存储的资源是否彼此一致。\r\n```\r\nLast-Modified: \u003cday-name\u003e, \u003cday\u003e \u003cmonth\u003e \u003cyear\u003e \u003chour\u003e:\u003cminute\u003e:\u003csecond\u003e GMT\r\n```\r\n\r\n5.4 条件式实体标签再验证\r\n\r\n有些文档可能会被周期性地重写（比如，从一个后台进程中写入），但实际包含的数据常常是一样的。尽管内容没有变化，但修改日期会发生变化。或者所做修改并不重要。还有有些文档会在亚秒间隙发生变化（比如，实时监视器），对这些服务器来说，以一秒为粒度的修改日期可能就不够用了。\r\n\r\n- `If-None-Match`请求首部当且仅当服务器上没有任何资源的 ETag 属性值与这个首部中列出的相匹配的时候，服务器端才会返回所请求的资源，响应码为 200 。\r\n```\r\nIf-None-Match: \u003cetag_value\u003e\r\nIf-None-Match: \u003cetag_value\u003e, \u003cetag_value\u003e, …\r\nIf-None-Match: *\r\n```\r\n- `ETag`HTTP 响应头是资源的特定版本的标识符。值为ASCII 字符串，通常，使用内容的散列，最后修改时间戳的哈希值，或简单地使用版本号。\r\n```\r\nETag: W/\"\u003cetag_value\u003e\"\r\nETag: \"\u003cetag_value\u003e\"\r\n```\r\n\r\n5.5 如何选择使用缓存再验证\r\n\r\n- 当与 If-Modified-Since 一同使用的时候，If-None-Match 优先级更高（假如服务器支持的话）\r\n\r\n5.6 试探性过期\r\n\r\n如果响应中没有Cache-Control:max-age首部，也没有Expires首部，缓存可以计算出一个试探性最大使用期。可以使用任意算法，但如果得到的最大使用期大于24小时，就应该向响应首部添加一个Heuristic Expiration Warning（试探性过期警告，警告13）首部。据我们所知，很少有浏览器会为用户提供这种警告信息。\r\n\r\n`LM-Factor算法`是一种很常用的试探性过期算法思路：\r\n- 如果已缓存文档最后一次修改发生在很久以前，它可能会是一份稳定的文档，不太会突然发生变化，因此将其继续保存在缓存中会比较安全。\r\n- 如果已缓存文挡最近被修改过，就说明它很可能会频繁地发生变化，因此在与服务器进行再验证之前，只应该将其缓存很短一段时间。\r\n\r\nLM-factor算法计算新鲜周期:\r\n\u003cimage src=\"https://user-images.githubusercontent.com/38830527/204340804-fa6556df-4056-4a24-bc90-f88e873041c3.png\" style=\"width:300px;\"/\u003e\r\n\r\n如果最后修改日期也没有的话，缓存就没什么信息可利用了。缓存通常会为没有任何新鲜周期线索的文档分配一个默认的新鲜周期（通常是一个小时或一天）。\r\n\r\n6. 设置缓存控制\r\n\r\n6.1 通过HTTP-EQUIV控制HTML缓存\r\nHTML 2.0定义了\u003cMETA HTTP-EQUIV\u003e标签。这个可选的标签位于HTML文档的顶部，定义了应该与文档有所关联的HTTP首部。\r\n```html\r\n\u003cHTML\u003e\r\n  \u003cHEAD\u003e\r\n    \u003cTITLE\u003eMy Document\u003c/TITLE\u003e\r\n    \u003cMETA HTTP-EQUIV=\"Cache-control\" CONTENT=\"no-cache\"\u003e\r\n  \u003c/HEAD\u003e\r\n最初，HTTP-EQUIV标签是给Web服务器使用的。如HTML RFC 1866所述，Web服务器应该为HTML解析\u003cMETA HTTP-EQUIV\u003e标签，并将规定的首部插入HTTP响应中：\r\n          ...\r\n```\r\nHTTP服务器可以用此信息来处理文档,在为请求此文档的报文所发送的响应中包含一个首部字段。但是通过这种方式可能会与拦截代理缓存所用的规则有所不同使缓存的过期处理行为发生混乱。\r\n\r\n### reference\r\n---\r\n### HTTP caching standard：[https://httpwg.org/specs/rfc9111.html](https://httpwg.org/specs/rfc9111.html)\r\n### 《HTTP权威指南》David Gourley，Brian Totty \r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flevelopers%2Fnotes-web-cache","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flevelopers%2Fnotes-web-cache","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flevelopers%2Fnotes-web-cache/lists"}