如何禁用通过 IIS 提供的单页应用程序 HTML 文件的缓存?
Posted
技术标签:
【中文标题】如何禁用通过 IIS 提供的单页应用程序 HTML 文件的缓存?【英文标题】:How to disable caching of single page application HTML file served through IIS? 【发布时间】:2014-12-23 09:58:37 【问题描述】:我有一个通过 IIS 提供服务的单页应用程序 (angular-js)。如何防止缓存 html 文件?该解决方案需要通过更改 index.html 或 web.config 中的内容来实现,因为无法通过管理控制台访问 IIS。
我目前正在研究的一些选项是:
web.config 缓存配置文件 - http://www.iis.net/configreference/system.webserver/caching web.config 客户端缓存 - http://www.iis.net/configreference/system.webserver/staticcontent/clientcache 元标签 - Using <meta> tags to turn off caching in all browsers?IIS 是 .NET 框架 4 的 7.5 版
【问题讨论】:
【参考方案1】:在提供您的 html 文件时,您可以附加一个随机查询字符串。即使文件在浏览器缓存中,这也会阻止浏览器使用旧版本。
/index.html?rnd=timestamp
另一个选项是在 IIS 级别添加无缓存设置。这会在响应中添加 Cache-Control: no-cache,告诉浏览器不要缓存文件。它从 IIS 7 开始工作。
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- Note the use of the 'location' tag to specify which
folder this applies to-->
<location path="index.html">
<system.webServer>
<staticContent>
<clientCache cacheControlMode="DisableCache" />
</staticContent>
</system.webServer>
</location>
</configuration>
【讨论】:
关于在 URL 中添加时间戳 - 是的,这可行,但我认为这更像是一种临时破解,而不是解决方案。我不相信任何有信誉的 SPA 解决方案都使用这种方法。 不要忘记您的 ng 路由、css 和 javascript。您执行此操作的方式是 web.config for index.html。 ?v=1 对于其他所有内容,例如main.css?v=1. 大多数情况下,像 index.html 这样的登陆页面不是由应用内代码请求的,而是由最终用户请求的,他们只需在浏览器中指定地址,不会附加随机时间戳?所以“另一种选择”是要走的路??【参考方案2】:将以下内容添加到 web.config
解决方案中适用于 Chrome、IE、Firefox 和 Safari:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<location path="index.html">
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Cache-Control" value="no-cache" />
</customHeaders>
</httpProtocol>
</system.webServer>
</location>
</configuration>
这将确保在请求 index.html
时将 Cache-Control
标头设置为 no-cache
。
【讨论】:
我认为这仅在点击直接包含 index.html 的 url 时才有效。SPA 中的所有请求都有虚拟 url,并且不映射到真实的位置路径。可以用它做什么? @MichailMichailidis 对于 SPA,您可能有一个规则将您的网址重写为“/”?如果您也添加该路径怎么办? 虽然这个答案在技术上是准确的,但我认为值得指出的是Cache-Control: no-cache
不会禁用缓存,而是强制客户端检查源服务器。因此,它与etag
标头或可能不可靠的last-modifed
标头协同工作,但它不会彻底禁用缓存。来自 no-cache
的 MDN:“在使用缓存副本之前,缓存必须与源服务器检查以进行验证。”换句话说,如果服务器没有返回 304,浏览器可能仍然使用缓存副本。
为了解决@MichailMichailidis 的问题,请确保您的全面重写规则为<action type="Rewrite" url="/index.html" />
或查看this link 以获取完整的Web.config
【参考方案3】:
对于 .NET Core,我使用了以下内容。
app.UseStaticFiles(new StaticFileOptions
OnPrepareResponse = context =>
if (context.File.Name == "index.html" )
context.Context.Response.Headers.Add("Cache-Control", "no-cache, no-store");
context.Context.Response.Headers.Add("Expires", "-1");
);
感谢How to disable browser cache in ASP.NET core rc2?
【讨论】:
我对 React 不是很熟悉(只是想解决我们的缓存问题),但是对我来说,在调试的时候,在上面的if
语句上有一个断点,这个断点没有命中index.html
。我尝试将代码放在app.UseStaticFiles
和app.UseSpaStaticFiles
中。第二个是favicon.ico
和manifest.json
,位于与index.html
相同的文件夹中。有什么想法吗?
@Kjell Rilbe,如果没有为index.html
命中断点,请在浏览器控制台中验证它是从服务器请求的,而不是浏览器缓存。如果浏览器正在缓存,那么您需要解决以前没有缓存控制标头的index.html
文件的情况,因此浏览器不知道服务器的更改。目前我不记得如何解决这个问题(将无用的查询字符串附加到路径,手动清除浏览器缓存一次可能有助于调试)。祝你好运。
谢谢,我会再检查一次(我想我已经做过了,但要确保)。断点只被命中两次,这就是我提到的文件,尽管浏览器实际上似乎获取了许多其他资源。页面index.html
可能是作为默认文档/根 URL 获取的,没有指定路径或文件,这就是为什么我在if
上放置一个断点,以查看context.File.name
在该场景中实际出现的内容。但是……没什么……【参考方案4】:
<meta http-equiv="cache-control" content="no-cache, must-revalidate, post-check=0, pre-check=0">
【讨论】:
该标头仅适用于 index.html 文件还是也适用于其中包含的所有内容? (css, js, 图片,...) 我认为只适用于 index.html【参考方案5】:SPA 的主要前提是从不缓存 index.html
在MDN recommendations to prevent caching 之后,我们必须添加 Cache-Control HTTP 标头和 no-store, max-age=0 资源的值(在我们的例子中是 index.html 文件)。
为什么 no-store 而不是 no-cache?
使用 no-store,资源不会存储在任何地方。使用no-cache,资源可能会被存储,但在使用前需要通过存储与服务器进行验证。
为什么max-age=0?
强制清除预先存在的有效缓存响应(no-store 不会)。
在 IIS 中,我们可以通过 web.config 文件管理我们的应用缓存配置。这是一个完整的 web.config 文件(必须位于我们应用程序的根目录中),其中包括 index.html 文件的缓存配置以及路由配置(我已经添加了 SPA 路由和 HTTP 重定向到 HTTPS 作为示例):
<configuration>
<location path="index.html">
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Cache-Control" value="no-store, max-age=0" />
</customHeaders>
</httpProtocol>
</system.webServer>
</location>
<system.webServer>
<rewrite>
<rules>
<rule name="HTTP to HTTPS" enabled="true" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="HTTPS" pattern="^OFF$" />
</conditions>
<action type="Redirect" url="https://HTTP_HOSTREQUEST_URI" />
</rule>
<rule name="SPA Routes" enabled="true" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="REQUEST_FILENAME" matchType="IsFile" negate="true" />
<add input="REQUEST_FILENAME" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="/index.html" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
【讨论】:
【参考方案6】:这些答案都不适合我,因为正如@MichailMichailidis 所提到的,“SPA 中的所有请求都有虚拟 url,并且不映射到真实的位置路径”,所以 location path
从不匹配index.html
。
我在这个blog post 中找到了解决方案,它链接到this answer。两者都向您展示了如何使用重写模块的outboundRules
根据条件更改cache-control
响应标头。
所以这就是我的 web.config 在这个配置之后的样子:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<rewrite>
<outboundRules>
<rule name="RewriteCacheControlForIndexHtmlFile"
preCondition="IsIndexHtmlFile">
<match serverVariable="RESPONSE_Cache_Control" pattern=".*" />
<action type="Rewrite" value="max-age=0" />
</rule>
<preConditions>
<preCondition name="IsIndexHtmlFile">
<add input="REQUEST_FILENAME" pattern="index.html" />
</preCondition>
</preConditions>
</outboundRules>
...
【讨论】:
以上是关于如何禁用通过 IIS 提供的单页应用程序 HTML 文件的缓存?的主要内容,如果未能解决你的问题,请参考以下文章
HTML6 无 JavaScript 的单页应用引起一片哗然
IIS / AngularJS单页应用程序-在应用程序中导航时如何防止单个index.html的页面缓存
如何设置NGINX以根据位置(在相同的server_name下)部署不同的单页应用程序(SPA的...即静态文件)和子路由