HTML5 - 在Chrome上缓存清单正常工作,但在Firefox和Opera上却不行。

21

我正在开发一个用于离线使用的Web应用程序,因此需要使用应用程序缓存功能。

在Chrome(15.0.874.106)上一切正常,但在Firefox(7.0.1)和Opera(11.52)上不起作用。

这是我的缓存清单文件cache.manifest.php(已将其减少到最少):

<?php 
    header("Cache-Control: max-age=0, no-cache, no-store, must-revalidate");
    header("Pragma: no-cache");
    header("Expires: Wed, 11 Jan 1984 05:00:00 GMT");
    header('Content-type: text/cache-manifest');
?>CACHE MANIFEST

CACHE:

/app/common/css/reset.css
/favicon.ico

这是“主”HTML文档的前4行:

<!DOCTYPE html> 
<html manifest="/app/mobile/cache.manifest.php"> 
    <head> 
    <title>MyApp Mobile</title> 
当我尝试加载缓存清单(http://www.myapp.com/app/mobile/cache.manifest.php)到浏览器中时,文件能够正确显示,但是离线加载页面时我会收到“无法连接”的错误页面。这种情况只发生在Firefox和Opera浏览器上。
Firebug显示“离线缓存中的0个项目”,而我找不到在DragonFly上检查应用程序缓存的方法。
我很烦恼,不知道如何有效地调试Firefox和Opera上的问题,请帮忙。
谢谢, Dan

为了确保,您首先打开了“main”HTML文档,并允许Firefox离线存储您的站点数据?您没有明确说明这一点。简化的不工作版本是否可以在网上找到?我敢打赌这会更容易回答。 - Nickolay
1
好的一点是:我确实给了Firefox存储缓存清单的机会,因为我开着互联网。但是一旦我关闭互联网并重新加载页面,它就不再起作用了 - 它会给我显示“无法连接”的消息。 - Dan
@dan,为什么不把“main”页面添加到缓存中呢? - Gabriele Petrioli
@muntoo:就像我之前说的,我快要疯了。已经有将近一年的时间,我没有被一个技术产品卡住这么长时间了。 - Dan
你们有一个我们可以试玩的实时演示吗? - AshleysBrain
显示剩余3条评论
13个回答

15

根据我的经验,使用HTML5 AppCache是非常好的,一旦它起作用了。但是它极其脆弱。只要有一点问题,浏览器就会忽略整个文件,并且很烦人的是,它不会使用浏览器的普通缓存,而是从服务器重新加载所有内容。

更糟糕的是,浏览器不会重新加载清单文件,除非它的文本内容发生了变化。所以你可能会调整服务器标头或其他东西来解决问题,但是除非cache.manifest.php的内容发生了改变,否则浏览器将盲目地忽略它,并且执行与上次完全相同的操作。这甚至似乎免疫于清除浏览器缓存,这也是使它如此令人困惑的一部分 - 应用程序缓存真的非常严格。

为了解决这个问题,注释中的文本变化也算数,因此在顶部添加一个版本、时间戳或日期的注释(例如# 版本1.2),并在需要让浏览器“注意”时更改它。

然后,浏览器仍然不会立即使用它!应用程序缓存的工作方式是,在下次加载页面时,它将再次执行与上次完全相同的操作,并在后台开始检查更新。因此,您可能需要打开控制台,等待类似“正在更新…”然后“完成”的消息,然后点击刷新按钮,浏览器最终会开始使用新版本。终于!

总之,让它起作用可能非常麻烦。但是一旦它运行起来,几乎就可以保证清单中列出的任何内容只会被每个用户下载一次永远,直到您更改文件的文本内容。

现在浏览器的标准合规性相当好,所以我的最佳猜测是你实际上已经让它工作了,但是你最后检查的是Chrome,并且它是唯一一个正确缓存清单文件的浏览器。在开发过程中,你可能已经搞砸了Firefox和Opera,它们还固执地抱着旧的清单文件不放。我敢打赌你也尝试过在Firefox和Opera中清除浏览器缓存,但这可能没有用-你需要更改文件的文本内容并进行双重刷新,然后Firefox和Opera才会最终放弃它们错误的清单文件版本并开始使用那个适合你很久以前上传的可用版本。


感谢您的帮助。事实是应用程序缓存根本不起作用 - 这不是使用旧版本的问题。 - Dan
2
另一种解决方案是生成缓存清单文件并在清单中包含所有文件的MD5。这样,如果任何文件更改,清单就会更改(因为文件的MD5已更改)。 - jedison

9

来源: http://appcache.offline.technology

在 Firefox 中,任何使用 Cache-control: no-store 服务的资源都不会被缓存,即使它们明确地包含在清单中。

我的 PHP 默认发送:

Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0

只需要添加以下代码即可:

header("Cache-Control: no-cache, must-revalidate");

将php文件启用缓存。

(这与Mychal Hackman的回答类似,但更加具体。)


3
对我来说,你的缓存清单看起来有点“不寻常”......添加一个FALLBACK部分可能会有帮助......另一点是,应用程序缓存可能会干扰“普通浏览器缓存”,即如果缓存清单更改,则需要确保浏览器重新加载它,理想情况下通过更改名称来实现(例如通过版本号、时间戳...作为名称的一部分)。
您可以通过JS在页面中与appcache进行交互,这可能有助于确定您看到的问题。
有关深入信息,包括JS代码和彻底的演示,请参见 如果需要的话,请提出具体问题。
更新
根据 OP 提供的评论,this 显示了一个很好的 JS API 实现,用于检查/调试应用缓存,就像上面链接中描述的那样。

1
这是一个关于如何使用JS调试应用程序缓存的好链接:http://jonathanstark.com/blog/2009/09/27/debugging-html-5-offline-application-cache/ - Dan
@dan 没问题 :-) 是的,这个链接提供了一个不错的实现方法... 我已经将它添加到答案中以备将来参考。 - Yahia

3
您可以使用window.applicationCache.status来检查应用程序缓存的当前状态,它会返回与以下状态相对应的数字值:0 - 未缓存1 - 空闲2 - 正在检查3 - 正在下载4 - 更新就绪5 - 废弃。 应用程序缓存API有一些需要注意的事项: window.applicationCache.update():这将触发应用程序缓存下载过程,几乎与重新加载页面相同。它只是检查清单是否已更改,如果是,则下载缓存中所有内容的新版本(遵守任何缓存标头)。请注意,即使使用此方法创建了新缓存,页面仍将继续使用旧缓存。要使页面使用刚刚下载的新缓存,必须使用swapCache()函数。 window.applicationCache.swapCache():此函数告诉浏览器开始使用新的缓存数据(如果可用)。重要的是,即使有新的清单文件,应用程序仍将继续使用旧缓存(如旧清单文件中指定的那样),直到调用swapCache()。一旦调用了swapCache(),则将按照新清单文件中指定的方式使用缓存。
来源:http://dev.opera.com/articles/view/offline-applications-html5-appcache/

3

请在 about:cache 中检查您的缓存。我敢打赌您会发现您的 PHP 文件的“数据大小为 0 字节”。

检查您的缓存标头,在 Firefox 中我发现我的 PHP 文件的默认值是“no-cache”。我只需添加以下内容:

header("Pragma: public");
header("Cache-Control: public, max-age=6000");

我将我的PHP文件更改后重新加载了离线缓存,现在它终于可以工作了。

希望这能有所帮助。


2
尝试删除以下内容:
header("Cache-Control: max-age=0, no-cache, no-store, must-revalidate");
header("Pragma: no-cache");
header("Expires: Wed, 11 Jan 1984 05:00:00 GMT");

这样你只需要发送Content-type头部信息:

<?php header('Content-type: text/cache-manifest'); ?>

ApplicationCache会强制缓存(过于简化,但并不夸张)。前三个标头是防止缓存的方法。
当这些标头存在时,Opera似乎会阻止缓存。Firefox的调试工具在调试AppCache时有点问题,但可以安全地假设这也会在那里解决问题。

很有趣的观点,Webinista。我能预见到的唯一问题(而且是个大问题)是,即使缓存文件的内容发生改变,浏览器也不会更新缓存清单。您对此有何想法? 你有支持你理论的链接吗? - Dan
嗯,看起来这些头文件实际上不会有太大的影响。话虽如此,如果缓存清单文件发生更改,浏览器将更新缓存。因此,如果您在reset.css中进行更改,请通过添加或更改注释来同时更改cache.manifest.php。另外一个要尝试的事情是使用JavaScript添加清单属性。 - webinista
"使用JavaScript添加清单属性" - 有趣的想法:您认为这会有什么帮助?此外,我应该在什么时候添加它? - Dan
我曾经遇到过类似的问题,发送 Cache-control: no-store 导致 Firefox 拒绝清单(window.applicationCache 的 error 事件被调用)。所以,显然 Firefox 对 HTTP 标头很敏感。另一方面,Firefox 接受 Cache-control: no-cachePragma: no-cacheExpires: 0 - Udo G

2
对于Firefox浏览器,可以尝试这个小技巧:
<html manifest="/app/mobile/cache.manifest.php?1"> 

是 "?1" 最终使 Firefox 检查最新文件。无论如何,这就是我的解决方法。希望能帮到你。


1

根据我在iPad上离线运行网站的经验:

  • 文件名需要以.manifest结尾
  • mime类型需要是text/cache-manifest
  • 在清单的注释中添加版本号
  • 使用window.applicationCache...创建一些JavaScript函数,检查浏览器是否看到了清单中的更改并重新加载内容,同时捕获状态事件并在某个地方显示它们

另请参阅: http://developer.apple.com/library/safari/#documentation/iPhone/Conceptual/SafariJSDatabaseGuide/OfflineApplicationCache/OfflineApplicationCache.html#//apple_ref/doc/uid/TP40007256-CH7-SW1


1
您不需要手动包含 HTML 页面,它会自动被包含。 - OlliM

1

我遇到了类似的问题。虽然我的回答很晚,但这可能对其他人有所帮助。确保您不会遇到AshleysBrian在他的答案中描述的问题。除此之外还要注意:

  1. 确保清单文件的类型为"text/cache-manifest"
  2. 不要在Firefox/IE的隐私浏览模式下尝试。它只在常规浏览模式下工作。但在Chrome中两种模式都可以使用
  3. 离线时,URL中的简单更改可能会导致问题

    例如:http://localhost:8080/app在Firefox/IE上无法运行
    但是http://localhost:8080/app/在Firefox/IE上可以运行
    

    两者在Chrome中都可以运行

  4. 使用这些方便的资源查看器以获得更详细的视角

    about:cache - Firefox
    chrome://appcache-internals/ - Chrome
    如果有人知道IE是什么,请填写
    

0

我找到了类似的东西,并将其追踪到清单上的Cache-Control: no-store标题。Chrome接受此操作,但Firefox会默默失败。

我的测试表明,您可以保留no-cache头和expires头以确保频繁刷新。


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