如何使浏览器停止缓存GWT nocache.js文件

10
我正在使用GWT开发Web应用程序,但在浏览器中看到了一个奇怪的问题,即使Web服务器发送了新文件的副本,浏览器仍然缓存了app.nocache.js文件。我使用Eclipse编译该应用程序,在dev模式下工作正常。为了测试生产模式,我有一个虚拟机(Oracle VirtualBox),其Ubuntu客户端OS在我的主机(Windows 7)上运行。我在VM中使用lighttpd web服务器。VM共享我的项目war目录,并由Web服务器提供此目录。我正在使用Chrome浏览器,但是Firefox也会出现同样的问题。这是情景:1.应用程序的Web页面是空白的,因为它正在尝试获取不存在的6E89D5C912DD8F3F806083C8AA626B83.cache.html文件(404未找到)。2.我检查了war目录,确实没有该文件。3.浏览器中的app.nocache.js已从Web服务器重新加载(200 OK),因为服务器上的文件比浏览器缓存的文件更新。我验证了服务器返回的新文件的文件大小和时间戳是否正确。(这是Chrome报告的有关服务器HTTP响应的信息)4.但是,如果我在浏览器中打开app.nocache.js,则JavaScript引用的是6E89D5C912DD8F3F806083C8AA626B83.cache.html!!!也就是说,即使Web服务器发送了新的app.nocache.js,浏览器似乎会忽略它并继续使用其缓存的副本!5.在Eclipse中转到Google-> GWT Compile。重新编译整个内容。6.验证war目录中app.nocache.js已被覆盖并具有新的时间戳。7.从Chrome重新加载页面,并再次验证服务器是否向app.nocache.js发送了200 OK响应。8.浏览器再次尝试加载6E89D5C912DD8F3F806083C8AA626B83.cache.html,但失败了。浏览器仍在使用旧的缓存副本app.nocache.js。9.确保在war目录中没有任何东西引用6E89D5C912DD8F3F806083C8AA626B83.cache.html(通过查找和grep进行)。
为什么浏览器会缓存这个nocache.js文件,即使服务器正在发送新的副本?以下是单击浏览器中的重新加载时HTTP请求/响应头的副本。在此跟踪中,自上次GET以来未重新编译服务器内容(但请注意,nocache.js的缓存版本仍然是错误的!):
Request URL:http://192.168.2.4/xbts_ui/xbts_ui.nocache.js
Request Method:GET
Status Code:304 Not Modified
Request Headersview source
Accept:*/*
Accept-Charset:ISO-8859-1,utf-8;q=0.7,*;q=0.3
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Cache-Control:max-age=0
Connection:keep-alive
Host:192.168.2.4
If-Modified-Since:Thu, 25 Oct 2012 17:55:26 GMT
If-None-Match:"2881105249"
Referer:http://192.168.2.4/XBTS_ui.html
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4
Response Headersview source
Accept-Ranges:bytes
Content-Type:text/javascript
Date:Thu, 25 Oct 2012 20:27:55 GMT
ETag:"2881105249"
Last-Modified:Thu, 25 Oct 2012 17:55:26 GMT
Server:lighttpd/1.4.31

顺便提一下,这似乎与https://dev59.com/eHA75IYBdhLWcg3wOWVd相似,但它并没有包含任何有助于解决此问题的信息。 - jfritz42
你有没有阅读过 https://developers.google.com/web-toolkit/doc/latest/DevGuideCompilingAndDebugging#perfect_caching ? - Andrei Volgin
是的,而且似乎发生了正确的事情,因为那个页面上说“一个If-Modified-Since获取就足够了”。我可以从Chrome检查元素工具中看到浏览器在GET请求中发送了“If-Modified-Since:Thu,25 Oct 2012 17:03:53 GMT”,而服务器响应了“Last-Modified:Thu,25 Oct 2012 17:55:26 GMT”。 - jfritz42
添加了HTTP请求/响应头跟踪,以使潜在的帮助者更清晰明了。 - jfritz42
我怀疑问题在于浏览器对nocache.js文件的新鲜度寿命进行了猜测,并确定该文件仍然“新鲜”。这是从阅读HTTP RFC第13.2.4节得出的:“如果响应中没有Expires、Cache-Control:max-age或Cache-Control:s-maxage(见第14.9.3节),并且响应不包括其他缓存限制,则缓存可以使用启发式方法计算新鲜度寿命。”(来自http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13) - jfritz42
遇到相同的问题,这是gwt2.7.0中的错误,当我降级到2.6.0时,问题消失了。 - skyCsky wang
6个回答

5

避免浏览器缓存的最佳方法是将过期时间设置为现在,并添加max-age=0和must-revalidate控件。

这是我在apache-httpd中使用的配置。

ExpiresActive on
<LocationMatch "nocache">
   ExpiresDefault "now"
   Header set Cache-Control "public, max-age=0, must-revalidate"
</LocationMatch>
<LocationMatch "\.cache\.">
   ExpiresDefault "now plus 1 year"
</LocationMatch>

你的lighthttpd配置应该如下:

server.modules = (
    "mod_expire",
    "mod_setenv",
)
...
$HTTP["url"] =~ "\.nocache\." {
  setenv.add-response-header = ( "Cache-Control" => "public, max-age=0, must-revalidate" )
  expire.url = ( "" => "access plus 0 days" )
}

$HTTP["url"] =~ "\.cache\." {
  expire.url = ( "" => "access plus 1 years" )
}

谢谢。我在 lighttpd 配置中修复了一些打字错误。感谢您将 Apache 配置翻译成 lighttpd。 - jfritz42

5
我们曾遇到类似的问题。我们发现nocache.js的时间戳在gwt编译时没有更新,所以必须在构建时touch文件。然后我们还应用了@Manolo Carrasco Moñino的修复程序。我写了一篇关于这个问题的博客。http://programtalk.com/java/gwt-nocachejs-cached-by-browser/
正如评论中所指出的那样,我们使用的是2.7版本的GWT。

1
时间戳不变是我们的问题。我相信这只是GWT 2.7中的一个错误。感谢您的博客文章! - Craigo
很好的答案。现在我第一次学到了Shift+F5是一个临时解决方案。 - Tom

3

有两个简单的解决方案(第二个是第一个的修改版本)

1)将包含对*.nocache.js引用的*.html文件重命名为例如MyProject.html到MyProject.jsp 现在在MyProject.html中查找*.nocache.js脚本的位置

<script language="javascript" src="MyProject/MyProject.nocache.js"></script>

为 JS 文件添加动态变量作为参数,这将确保每次从服务器返回实际内容。以下是示例:

<script language="javascript" src="MyProject/MyProject.nocache.jsp?dummyParam=<%= "" + new java.util.Date().getTime() %>"></script>

解释:dummyParam没有实际用途,但可以得到我们想要的结果,即返回200代码而不是304。
注意:如果您使用此技术,则需要确保指向正确的jsp文件来加载您的应用程序(在更改之前,您是使用HTML文件加载应用程序的)。
2)如果您不想使用JSP解决方案并希望坚持使用html文件,则需要使用java脚本在客户端动态添加唯一参数值来加载nocache文件。我假设现在对您来说这不是什么大问题,因为上面的解决方案已经给出了。
我已经成功使用了第一种技术,希望这会有所帮助。

2
在浏览器中,app.nocache.js从Web服务器重新加载(200 OK),因为服务器上的文件比浏览器缓存中的文件更新。我验证了服务器返回的新文件的文件大小和时间戳是正确的。(这是Chrome关于服务器HTTP响应的报告信息)
我不会依赖这个。我在使用Chrome的开发工具与网络选项卡以及缓存结合时看到了一些奇怪的行为(至少对我来说不是100%透明的)。如果有疑问,我通常仍然会使用Firebug。
所以可能Chrome仍在使用旧版本。它可能很久以前就决定再也不需要重新加载资源了。清除缓存应该解决此问题。然后,在重新加载页面之前,请确保设置正确的缓存标头,例如参见Ideal HTTP cache control headers for different types of resources

0

打开隐身模式以消除缓存问题并解除封锁。

您需要根据其他评论中提到的配置缓存时间。


-1

在尝试通过Apache防止缓存失败后,我创建了一个bash脚本,并且将其设置为根用户在我的Linux Tomcat服务器上每分钟运行一次的cron工作。

#!/bin/bash
#
# Touches GWT nocache.js files in the Tomcat web app directory to prevent caching.
# Execute this script every minute in a root cron job.
#
cd /var/lib/tomcat7/webapps
find . -name '*nocache.js' | while read file; do
    logger "Touching file '$file'"
    touch "$file"
done

使用根脚本来触碰由您的Web服务器提供的文件真的是一个坏主意 - 特别是因为您应该做的是确保内容与适当的HTTP标头一起提供(如果浏览器或中间代理以善意缓存了内容,则甚至不会询问您的服务器)。 - R4zorax

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