0

最近、Web アプリ (フルスクリーン) モードで iOS 6.x デバイスを実行しているときに、GWT アプリのキャッシュに関連する問題を発見しました。問題は、iOS がかさばる順列ファイル( <hash>.cache.html.)に対する私のキャッシュ ポリシー ディレクティブを無視しているように見えることです。

*.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" />

この問題がどこにも文書化されているのを見つけることができず、それがバグであるとは確信していません。しかし、それは私が経験したことです。キャッシュは、受信したヘッダーを検査できるデスクトップ ブラウザーで期待どおりに機能します。すべてのクライアントが同じヘッダーを受け取るように、ユーザー エージェントをスニッフィングしてこの情報に基づいて区別することはありません。


この Google I/O トークで紹介されているように、HTML5 キャッシュ マニフェスト ファイルを介して差し迫った問題を「解決」することができました: 「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">
...

すべてのクライアントがすべての順列をロードする必要があることを除いて、これはすべて問題ありませんが、必要なのは1 つだけです! 私の場合、3Gまたはエッジでそれぞれ約5MBの18の順列です:(これは本当に最善の解決策ですか?

4

1 に答える 1

0

私が最終的に行ったことは、もう少し調査した結果、マニフェスト参照をホスト ページに追加する代わりに、すべての順列スクリプトに追加できることがわかりました。マニフェスト自体は、一般的な (そして実質的に空の) ファイルにすることができます。

作成者はマニフェストにもメイン ページを含めることをお勧めしますが、実際には、明示的に言及されていなくても、マニフェストを参照したページは自動的にキャッシュされます。(ソース

したがって、私は簡単に次のように書きましたLinker

  1. オフライン マニフェスト ファイルを作成します
  2. すべての順列スクリプトmanifestのタグに属性を追加します ( )。<html>*.cache.html

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 MANIFEST\n")
               .append("# Generated by ")
               .append(getClass().getSimpleName())
               .append(": ")
               .append(System.currentTimeMillis())
               .append(".\n\n")
               .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" />
    ...

また、 my を介して適切なコンテンツ タイプが設定されていることを確認します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:
*
于 2013-04-24T09:53:00.380 に答える