有几件事情需要考虑,并且有多种方法可以解决这个问题。一、the spec
我们想要完成什么?
理想情况下,修改后的资源将在第一次被请求时无条件地获取,然后从本地缓存中检索,直到它过期且没有后续服务器交互。
观察到的缓存行为
跟踪不同的排列可能有点令人困惑,因此我创建了下表。这些观察是通过从 Chrome 向 IIS 发出请求并观察开发者控制台中的响应/行为而生成的。
在所有情况下,新 URL 都会导致 HTTP 200。重要的是后续请求会发生什么。
+---------------------+--------------------+-------------------------+
| Type | Cache Headers | Observed Result |
+---------------------+--------------------+-------------------------+
| Static filename | Expiration +1 Year | Taken from cache |
| Static filename | Expire immediately | Never caches |
| Static filename | None | HTTP 304 (not modified) |
| | | |
| Static query string | Expiration +1 Year | HTTP 304 (not modified) |
| Static query string | Expire immediately | HTTP 304 (not modified) |
| Static query string | None | HTTP 304 (not modified) |
| | | |
| Random query string | Expiration +1 Year | Never caches |
| Random query string | Expire immediately | Never caches |
| Random query string | None | Never caches |
+---------------------+--------------------+-------------------------+
然而,请记住浏览器和网络服务器并不总是按照我们预期的方式运行。一个著名的例子:in 2012 mobile Safari began caching POST requests。开发者不高兴。
查询字符串
ASP.Net MVC Razor 语法中的示例,但几乎适用于任何服务器处理语言。
...因为一些应用程序传统上使用 GET 和 HEAD
查询 URL(在 rel_path 部分中包含“?”的那些)以执行
具有显着副作用的操作,缓存不得处理
对此类 URI 的响应是新鲜的,除非服务器提供了明确的
到期时间。这特别意味着来自 HTTP/1.0 的响应
此类 URI 的服务器不应从缓存中获取。
在 HTML 中包含的 CSS URL 的末尾附加一个随机参数将强制执行新请求,并且服务器应该以 HTTP 200(不是 304,即使它还没有响应)响应
修改)。
<link href="normalfile.css?random=@Environment.TickCount" />
当然,如果我们用每个请求随机化查询字符串,这将完全破坏缓存。 这对于生产应用程序来说很少/永远不可取。
如果您只维护几个 URL,您可以手动修改它们以包含内部版本号或日期:
@{
var assembly = Assembly.GetEntryAssembly();
var name = assembly.GetName();
var version = name.Version;
}
<link href="normalfile.css?build=@version.MinorRevision" />
这会在用户代理第一次遇到该 URL 时引发新的请求,但后续的请求大多会返回 304。这仍然会导致发出请求,但至少不会提供整个文件。
路径修改
更好的解决方案是创建一条新路径。只需稍加努力,这个过程就可以自动使用版本号(或其他一致的标识符)重写路径。
This answer 展示了一些适用于非 Microsoft 平台的简单而优雅的选项。
Microsoft 开发人员可以使用 HTTP 模块来拦截对给定文件类型的所有请求,或者可能利用 MVC 路由/控制器组合来提供正确的文件(我还没有看到这样做,但我相信是可行的)。
当然,最简单(不一定是最快或最好)的方法是在每个版本中重命名相关文件,并在 link 标签中引用更新后的路径。
TLDR
- 更改文件名或查询字符串
- 使用每个版本只发生一次的更改
- 文件重命名优于查询字符串更改
- 始终设置 HTTP 标头以最大限度地发挥缓存的优势