Flex

GZip compression + Flex(Flash Player) + IE6 = Nightmare

IE6 + mod_deflate(GZip圧縮) + Flex/FlashでFlashPlayerの無応答(もしくは動作不良)に対する解決策です。

以下、http://www.fxug.net/modules/xhnewbb/viewtopic.php?viewmode=flat&topic_id=3510&forum=16 に投稿した内容と重複します。

(■追記 - 2010/02/27 - この内容を編集しました。FxUGに投稿した内容と多少前後します。)


GZip compression + Flash Player + IE6 = Nightmare


先に参考にさせて頂いたURLをペタっと。

http://www.google.com/search?hl=ja&safe=off&rlz=1B3GGGL_jaJP336JP336&num=100&q=add-no-cache-headers&btnG=%E6%A4%9C%E7%B4%A2&lr=lang_ja&aq=&oq=
http://www.riaservice.com/?p=526
http://help.adobe.com/ja_JP/LiveCycleDataServicesES/3.0/Developing/WSc3ff6d0ea77859461172e0811f00f6e876-7fd6.html
http://www.adobe.com/support/documentation/jp/flex/2/releasenotes_flex2_fds.html



[ エラー内容 ]

デバッグ版FlashPlayer ver.10.0.32.18, IE6-SP1, Windows2000 Professionalでキャプチャしたエラー画面です。

flexError.jpg



[ 解決策 ]

結果としてはHTTPS + IEでの解決策と同様の手順になりました。
BlazeDS側にある WEB-INF\flex\services-config.xml を編集します。


    <channels>
        <channel-definition id="my-amf"
            class="mx.messaging.channels.AMFChannel">
            <!--
                ここで構成されたエンドポイントURLを mx:RemoteObjectのendpoint プロパティにセットする
                {}内は実行時に自動で置き換えられるのでこの記述のままで良い。
            -->
            <endpoint
                url="http://{server.name}:{server.port}/{context.root}/messagebroker/amf"
                class="flex.messaging.endpoints.AMFEndpoint" />
        </channel-definition>

の中に

<properties>
    <add-no-cache-headers>false</add-no-cache-headers>
</properties>

を記述するだけです。これで、mod_deflateやpjl-comp-filterなどによるGZip圧縮を有効にしても、ちゃんと動作するようにな ると思います。
下記の様に(endpoint以下に)properties部分を加えてWebコンテナを再起動して下さい。

    <channels>
        <channel-definition id="my-amf"
            class="mx.messaging.channels.AMFChannel">
            <!--
                ここで構成されたエンドポイントURLを mx:RemoteObjectの
                endpoint プロパティにセットする
                {}内は実行時に自動で置き換えられるのでこの記述のままで良い。
            -->
            <endpoint
                url="http://{server.name}:{server.port}/{context.root}/messagebroker/amf"
                class="flex.messaging.endpoints.AMFEndpoint" />
            <properties>
                <add-no-cache-headers>false</add-no-cache-headers>
            </properties>
        </channel-definition>

IEオプションのHTTP1.1を有効にして、URLにアクセスした時に動作すればOKかと。

結局パケットをキャプチャしてもダメだったので、デバッグ版FlashPlayerをIE6にインストールしてエラーメッセージを読みました。
エラーメッセージの内容は「NetConnection.Call.Failed: HTTP: Status 200」でしたので、それをキーワードにググったところIE + HTTPSの解決策と同じであることが判明致しましたので、ご報告とさせて頂きます。


以上。ご参考までに。

[ services-config.xml ]
-------
<?xml version="1.0" encoding="UTF-8"?>
<services-config>

    <services>
        <!-- service要素には何でもいいからIDが要る模様 -->
        <service id="remoting-service"
            class="flex.messaging.services.RemotingService">
            <adapters>
                <adapter-definition id="java-object"
                    class="flex.messaging.services.remoting.adapters.JavaAdapter"
                    default="true" />
            </adapters>
            <default-channels>
                <channel ref="my-amf" />
                <channel ref="my-secure-amf"/>
            </default-channels>

            <!-- destination要素のIDが mx:RemoteObjectの destination プロパティに対応する -->
            <!-- リモート呼び出しを可能にしたい Beanの数だけ destination要素を記述する -->
            <destination id="flexService">
                <properties>
                    <!-- リモート呼び出ししたいJava Beansのクラス名 -->
                    <source>com.chocbanana.ws.FlexService</source>
                    <!-- 注:この Beanはステートレスである -->
                </properties>
            </destination>
        </service>
    </services>

    <channels>
        <channel-definition id="my-amf"
            class="mx.messaging.channels.AMFChannel">
            <!--
                ここで構成されたエンドポイントURLを mx:RemoteObjectの
                endpoint プロパティにセットする
                {}内は実行時に自動で置き換えられるのでこの記述のままで良い。
            -->
            <endpoint
                url="http://{server.name}:{server.port}/{context.root}/messagebroker/amf"
                class="flex.messaging.endpoints.AMFEndpoint" />
            <properties>
                <add-no-cache-headers>false</add-no-cache-headers>
            </properties>
        </channel-definition>

        <!-- SSL用チャンネルの定義 -->
        <channel-definition id="my-secure-amf" class="mx.messaging.channels.SecureAMFChannel">
            <endpoint url="https://{server.name}:{server.port}/{context.root}/messagebroker/amfsecure" class="flex.messaging.endpoints.SecureAMFEndpoint"/>
            <properties>
                <add-no-cache-headers>false</add-no-cache-headers>
            </properties>
        </channel-definition>
    </channels>
</services-config>
[ EOF ]
-------



それでもエラーが出る場合は、↓の画像を参考にIEオプションも見直して下さい。

ieOption.jpg

このチェックが付いていると、上手く動かないんだと思います。
「暗号化されたページをディスクに保存しない」のチェックをOFFにして、再度確かめてください。


以下のURLが公式の回答ですね。
http://support.microsoft.com/kb/312496/ja
http://support.microsoft.com/kb/871205/ja


M$的には、
「HTTP 圧縮を使用している Web サーバーから返送されたデータの最初の 2,048 バイトが Internet Explorer で失われる」
「この問題は、コンピュータで Apache HTTP Server を実行していると発生する可能性が高くなります」
「Apache HTTP Server は、任意の種類のファイルでチャンク エンコードを使用できるため」
「IIS は、デフォルトではチャンク エンコードを使用しません」

だそうで、勘弁して下さい、M$さん。ホント。仕様だと回避策探すのが大変です。


MSのドキュメントでは

----------------------
この問題は、WININET と URLMON の間で通知が失われた場合に発生します。
通知が失われると、圧縮解除に必要なエンコードされたチャンクが失われます。
エンコードされたチャンクが失われると、gzip 圧縮解除プログラムが失敗します。

注)
WININET (Wininet.dll) は、HTTP データを受信するコンポーネントです。
URLMON (urlmon.dll) は、gzip 圧縮解除プログラムを実装するコンポーネントです。
----------------------

とあります。
で、IEでのGZipの解凍は urlmon.dll がやっているらしいので、バージョンを比較してみました。

urlmon_dll_img.jpg

エラーが出たのは 6.0.2800 のDLLを持ったWindows2000だけでした。
6.0.2900以上のバージョンのIE6ではエラーメッセージが出ませんでしたので、おそらくは多分、
urlmon.dllのバージョンによる不具合だと思われます。



■ 2010/02/27 - Windows2000 IE6-SP1のDLLをデバッグしてみました。 -

デバッグ対象であるDLLは WININET.DLLです。
URLMON.DLLはインストールされているDLLを使用しました。

んで、これのログを採ってみると...。

-----------------
21:59:49.054 0000024c:<app> 001 HttpQueryInfoA(0xcc000c, HTTP_QUERY_CONTENT_LENGTH (0x5), 0x12d774 [""], 0x12e9e8 [4168], 0x0 [0])
21:59:49.054 0000024c:<app> 001   *lpdwBufferLength = 3
21:59:49.054 0000024c:<app> 001   Query data:
21:59:49.054 0000024c:<app> 001   3 (0x3) bytes @ 0x12d774
21:59:49.054 0000024c:<app> 001   0012d774  36 37 35                                          675
21:59:49.054 0000024c:<app> 001 HttpQueryInfoA() returning TRUE

21:59:49.054 0000024c:<app> 001 HttpQueryInfoA(0xcc000c, HTTP_QUERY_CONTENT_DISPOSITION (0x2f), 0x12d774 [""], 0x12e9e8 [4168], 0x0 [0])
21:59:49.054 0000024c:<app> 001   HttpQueryInfoA() returning 12150 [ERROR_HTTP_HEADER_NOT_FOUND]
21:59:49.054 0000024c:<app> 001 HttpQueryInfoA() returning FALSE
-----------------

というエラーが延々と...。出ます...。orz
ここで、HttpQueryInfoA() returning 12150 [ERROR_HTTP_HEADER_NOT_FOUND] と HttpQueryInfoA() returning FALSE が出ているのが確認できます。

# 本来のログはもっともっと長いです。テキストで5MB近くになりました。追っかけるだけで死ねる...。orz

えー、つまりHTTPヘッダがぶっ千切られてますね。

これにブチ当たった場合、Flexのサーバー側を設定し、IEオプションを見直し、DLLのバージョンを確認して、出来ればDLLのデバッグを行って確認 して下さい。

...まぁIE6だけ...でしょうから。今後は良いと思うんですけどね...。
debug_log.txt

このページの先頭へ