如何确保网页内容从您的网站重新下载,而不使用缓存的临时互联网文件?

4
我注意到在更新网站内容文件(例如Silverlight XAP文件)时,浏览器不会检测到文件已更新,而是继续读取本地缓存的文件。由于这些文件很少更新,因此大部分时间应该从缓存的临时互联网文件中读取。
我的问题是是否有编程方法可以确保文件从网站下载,而不是从本地缓存读取,但仅当这些文件发生更改时?是否有广泛接受的处理此场景的过程?我不希望每个使用此Web产品的用户在安装更新时都必须删除其临时互联网文件。
这些文件只会在安装程序执行期间更新,因此我是否可以通过编程设置某些内容以确保这将发生?

服务器平台信息将更有帮助。 - AnthonyWJones
4个回答

2
你可以将一个随机数或日期时间值添加到查询字符串中。
这个问题大多数情况下发生在 AJAX 调用时。为了避免从缓存中取值,你可以构建一个查询字符串。
例如:
var xmlPath = "www.domain.com?vers="+new Date().getTime();+"";

1
这不是一个好的解决方案,因为版本号会每秒钟更改一次。实质上它根本不会被缓存。请参见下面我的解决方案以获得适当的解决方案。 - hobodave

1
迄今为止有许多编程解决方案。然而,解决方案就是简单地在服务器上配置ClientBin目录(或者你存储XAP文件的任何文件夹)。
假设使用IIS,你需要明确指定ClientBin文件夹立即过期。这将导致正确的缓存配置头在检索XAP时发送。反过来,浏览器每次需要它时都会尝试检索XAP文件,但在绝大多数情况下,它只会得到304未修改响应并且可以继续使用其缓存副本。
我猜您正在看IE启发式问题的经典情况。在没有任何缓存配置头的情况下,IE根据自己的内部算法决定是否要重新请求资源。通过确保发送正确的到期标头,IE将遵守服务器的指示。
编辑
似乎需要更清楚地说明此方法的操作。此方法不会使XAP资源未缓存且每次需要获取。
通过在IIS中指定立即过期功能,我们获得以下响应头:
HTTP/1.1 200 OK
Cache-Control: no-cache
Content-Length: 22359
Content-Type: application/octet-stream
Last-Modified: Tue, 21 Jul 2009 11:59:28 GMT
ETag: "fe734cb3fa9ca1:1352"

这并不会阻止 XAP 被缓存,它只是表示浏览器在未经服务器请求的情况下可能无法使用缓存的 XAP。请注意 Last-Modified 和 ETag 标头。

后续请求如下所示:

GET /clientBin/SomeApp.xap HTTP/1.1
If-Modified-Since: Tue, 21 Jul 2009 11:59:28 GMT
If-None-Match: "fe734cb3fa9ca1:135a"
Host: myhost.com

响应是:

HTTP/1.1 304 Not Modified
Cache-Control: no-cache
Last-Modified: Tue, 21 Jul 2009 11:59:28 GMT
Tag: "fe734cb3fa9ca1:135a"

这个响应没有实体主体,它允许浏览器使用缓存中现有的XAP。

如果XAP很大,则可能浏览器不会按照指定为no-cache的Cache-Control进行缓存。因此,更明确地设置可能更好。

不要使用“立即过期”框,而是使用自定义头列表配置Cache-Control标头。指定:

Cache-Control: max-age=0

这将导致浏览器缓存大型XAP文件,同时立即使它们过期。


如我在上面的评论中所述,这是一个糟糕的解决方案。不缓存大文件将会给他的Web服务器和用户的机器带来不必要的负担。请节约世界的带宽。 - hobodave
1
@hobodave:我认为你误解了缓存的工作原理。立即指定过期时间并不能阻止资源被缓存。它只是强制浏览器使用"If-Modified-Since"头请求资源。服务器可以响应304未修改的响应,其中不包含任何内容。 - AnthonyWJones

0

你的问题有点模糊,因为我不知道你在使用什么工具。我会用 PHP 举例。

你需要设置 Cache-Control 头来指定文件可以被缓存的最大时间。这个值是以秒为单位指定的。

例如:

<?php
header("Cache-Control","max-age=86400");

在将XAP文件发送给用户之前,您需要设置此标题。86400秒=1天。

另一种选择是为每个文件版本使用不同的文件名。您可以通过以下两种方式之一实现此目的。

在文件名中嵌入版本号:

some_file_1_1.xap
some_file_1_2.xap

或者,我的偏好是将版本号作为查询字符串附加到文件名后面:

some_file.xap?20090719
some_file.xap?20090720

您可以在 HTML 中使用相应的“版本”号引用这些文件,当版本号更改时,浏览器会将其视为文件名更改并强制重新下载。您可以使用任何您想要的“版本”字符串,其中的选项可能包括:修订号、最后修改日期字符串等。

如果您决定在每个修订版本中更改文件名,则建议使用“远期”缓存。确保文件被缓存的时间非常长,这将减少服务器的负载。您可以像上面使用 PHP 一样做到这一点,以下是一些使用 Apache 2.0 中的 mod_expires 的示例。

ExpiresActive on
ExpiresByType application/x-silverlight-app “access plus 5 years”
FileETag none

这种方法适用于小型、经常访问的资源,例如JS文件。但是,它需要所有引用都以这种方式装饰,并且更新资源需要同时更新所有引用。XAP通常比JS文件大得多,并且不像JS文件那样频繁请求流量。此外,Silverlight存在显着的启动延迟,因此将资源标记为立即过期对于XAP非常有效,因为小型304往返的延迟被Silverlight启动时间所掩盖。 - AnthonyWJones
该方法适用于任何文件。我不明白你是怎么得出结论的,因为XAP文件要大得多,所以让它们不被缓存是一件好事?好好想一想。节省互联网和他的Web服务器的带宽。OP没有询问如何以尽可能低的延迟方式执行此操作。他甚至明确表示,这些文件很少更改,只有在发布新版本的应用程序时才会更改。 - hobodave
@hobodave: 我推荐的方法不会使XAP未被缓存,也不需要每次重新获取XAP。只有在XAP与缓存的版本不同时,它才会被提取。我建议你查看HTTP 1.1规范,了解一下If-Modified-Since头和304未修改响应状态码。 - AnthonyWJones

0
我认为你也可以这样做:显然,这应该在每个页面都会使用的基类中完成。因此,创建一个继承自System.Web.UI.Page的PageBase,并使所有代码后台从PageBase继承。

或者在主控页中完成。

protected void Page_Init(object sender, EventArgs e) {
    Response.Cache.SetExpires(DateTime.UtcNow.AddMinutes(-1));
    Response.Cache.SetCacheability(HttpCacheability.NoCache);
    Response.Cache.SetNoStore();
}

如果您从ASPX页面生成XAP内容(基本上是一个Zip文件),那么这很好,但这可能不是您真正想要做的事情,也不是Phoenix正在做的事情。 - AnthonyWJones

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接