当支持web应用程序时,GWT-app排列脚本不会缓存到iOS设备上



最近我在iOS 6上运行时发现了一个与GWT应用缓存有关的问题。X设备在web-app(全屏)模式。问题是iOS似乎忽略了我对大容量排列文件的缓存策略指令 (<hash>.cache.html .)

我有一个servlet过滤器设置缓存头静态资源,包括*.cache.html文件,例如:

# Response header snippet
Expires: Fri, 26 Jul 2013 09:58:28 GMT
Cache-Control: public, max-age=8640000
ETag: W/"322107-1359629388000"
Last-Modified: Thu, 31 Jan 2013 10:49:48 GMT

然而,一旦我把web应用程序支持,并将应用程序添加到我的主屏幕,iOS设备将请求排列文件在每次加载,既不发送If-None-Match也不发送If-Modified-Since请求头。通过<meta>标签添加web应用程序支持:

<meta name="apple-mobile-web-app-capable" content="yes" />

我没能找到这个问题记录在任何地方,我不确定这是一个bug。然而,它就是我所经历的。在我的桌面浏览器中,缓存按预期工作,我可以检查收到的标头。我没有在任何地方嗅探用户代理并根据此信息进行区分,以便所有客户机都将收到相同的标头。


我能够通过HTML5缓存清单文件"解决"当前的问题,正如在这次Google I/O演讲中所展示的:"Google I/O 2010 - GWT链接器瞄准HTML5 WebWorkers &;其中自定义GWT链接器生成一个包含所有生成的排列的清单文件,例如:

CACHE MANIFEST
<hash1>.cache.html
<hash2>.cache.html
...
<hashN>.cache.html

并直接在主机页(<module>.html)中添加清单:

<!doctype html>
<html manifest="[module-path]/offline.manifest">
...

这一切都很好除了所有客户端现在必须加载所有排列,即使只需要一个 !在我的案例中,在3G或Edge上进行18次排列,每次约5MB:(这真的是最好的解决方案吗?

我最后做的是进一步调查,发现不是在主机页面中添加清单引用,我可以将它添加到所有排列脚本中。清单本身可以是一个通用的(实际上是空的)文件:

鼓励作者在清单中也包含主页,但实际上,即使没有明确提及,引用清单的页面也会自动缓存。(源)

因此,我写了一个简单的Linker:
  1. 创建脱机清单文件
  2. 为所有排列脚本(*.cache.html)的<html>标签添加manifest属性。

Linker被称为ManifestLinker,相当简单:

package com.example.linker;
// Imports
@LinkerOrder(Order.POST)
public class ManifestLinker extends AbstractLinker {
    private static final String MANIFEST_FILE = "manifest.nocache.appcache";
    private static final String HTML_FIND = "<html>";
    private static final String HTML_REPLACE = "<html manifest="" + MANIFEST_FILE + "">";
    /* (non-Javadoc)
     * @see com.google.gwt.core.ext.Linker#getDescription()
     */
    @Override
    public String getDescription() {
        return "`Manifest Linker`: Adds AppCache support for static `.cache.html` resources.";
    }
    @Override
    public ArtifactSet link(TreeLogger logger, LinkerContext context, ArtifactSet artifacts) throws UnableToCompleteException {
        ArtifactSet output = new ArtifactSet(artifacts);
        output.add(buildManifest(logger));
        for (EmittedArtifact artifact : artifacts.find(EmittedArtifact.class)) {
            if (artifact.getVisibility() == Visibility.Public && artifact.getPartialPath().endsWith(".cache.html")) {
                logger.log(TreeLogger.TRACE, "Processing file: " + artifact.getPartialPath());
                String cacheHtml = Util.readStreamAsString(artifact.getContents(logger));
                if (cacheHtml.startsWith(HTML_FIND)) {
                    cacheHtml = HTML_REPLACE + cacheHtml.substring(HTML_FIND.length()); // Replace `<html>` tag.
                    output.replace(copyArtifact(logger, artifact, cacheHtml));
                }
            }
        }
        logger.log(TreeLogger.INFO, "Manifest created and linked successfully.");
        return output;
    }
    private EmittedArtifact copyArtifact(TreeLogger logger, EmittedArtifact original, String contents) throws UnableToCompleteException {
        EmittedArtifact copy = emitString(logger, contents, original.getPartialPath());
        copy.setVisibility(original.getVisibility());
        return copy;
    }
    private EmittedArtifact buildManifest(TreeLogger logger) throws UnableToCompleteException {
        StringBuilder builder = new StringBuilder();
        builder.append("CACHE MANIFESTn")
               .append("# Generated by ")
               .append(getClass().getSimpleName())
               .append(": ")
               .append(System.currentTimeMillis())
               .append(".nn")
               .append("NETWORK:n")
               .append("*n");
        SyntheticArtifact manifest = emitString(logger, builder.toString(), MANIFEST_FILE);
        return manifest;
    }
}
在我的<module>.gwt.xml文件中,我定义并添加了链接器:
<?xml version="1.0" encoding="UTF-8"?>
<module>
    ...
    <define-linker name="manifest" class="com.example.linker.ManifestLinker" />
    <add-linker name="manifest" />
    ...

同时,我确保通过web.xml:

设置正确的内容类型
...
<mime-mapping>
    <extension>appcache</extension>
    <mime-type>text/cache-manifest</mime-type>
</mime-mapping>
...

发出的manifest.nocache.appcache也很简单:

CACHE MANIFEST
# Generated by ManifestLinker: 1366702621298.
NETWORK:
*

相关内容

  • 没有找到相关文章

最新更新