17

PHPで動的にロードされた画像をダウンロード(そしてできればキャッシュ)しようとしています。送受信されるヘッダーは次のとおりです。

リクエスト:

GET /url:resource/Pomegranate/resources/images/logo.png HTTP/1.1
Host: pome.local
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.22 (KHTML, like Gecko) Ubuntu Chromium/25.0.1364.160 Chrome/25.0.1364.160 Safari/537.22
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
Cookie: PHPSESSID=fb8ghv9ti6v5s3ekkmvtacr9u5

応答:

HTTP/1.1 200 OK
Date: Tue, 09 Apr 2013 11:00:36 GMT
Server: Apache/2.2.22 (Ubuntu)
X-Powered-By: PHP/5.3.14 ZendServer/5.0
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Disposition: inline; filename="logo"
ETag: "1355829295"
Last-Modified: Tue, 18 Dec 2012 14:44:55 Asia/Tehran
Keep-Alive: timeout=5, max=98
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: image/png

URL をリロードすると、まったく同じヘッダーが送受信されます。If-None-Match私の質問は、結果のリクエストでヘッダーを表示するには、レスポンスで何を送信すればよいですか?

注: これらのヘッダーは少し前まではうまく機能していたと思いますが、確信は持てませんが、ブラウザーはIf-None-Matchヘッダーを送信しないように変更されていると思います (以前はそのヘッダーを表示していました)。Chrome と Firefox でテストしていますが、どちらもヘッダーの送信に失敗します。

4

6 に答える 6

40

同じ問題、同様の解決策

If-None-Match開発中のサイトにアクセスしたときに Google Chrome がヘッダーを送信しない理由を突き止めようとしています。(Chrome 46.0.2490.71 m ですが、バージョンの関連性はよくわかりません。)

これは、最終的に引用されたOPとは異なる(非常に似ていますが)回答ですが(承認された回答に関するコメントで)、同じ問題に対処しています:

ブラウザーは、「必要な場合」に後続の要求でヘッダーを送信しませんIf-None-Match(つまり、最初の応答でETagorヘッダーを送信するために、PHP などを介したサーバー側のロジックが使用されています)。Last-Modified

前提条件

Chrome でロックを赤くする自己署名 TLS 証明書を使用すると、Chrome のキャッシュ動作が変わります。この性質の問題のトラブルシューティングを試みる前に、 https://stackoverflow.com/a/19102293で説明されているように、有効な信頼されたルート ストアに自己署名証明書をインストールし、ブラウザを完全に再起動してください。

最初のエピファニー: If-None-Match はサーバーからの ETag を必要とします。

サーバー以前のリクエストに応答してヘッダーを送信するIf-None-Matchまで、Chrome (およびおそらく他のほとんどまたはすべてのブラウザー) はヘッダーを送信しないことにすぐに気付きました。論理的には、これは完全に理にかなっています。結局のところ、値が与えられていない場合、Chrome はどのように送信できるのでしょうか? ETagIf-None-Match

これにより、サーバー側のロジック、特に、ユーザー エージェントに応答をキャッシュさせたい場合にヘッダーが送信される方法を調べて、ETagChrome の最初の応答でヘッダーが送信されない理由を特定しようとしました。リソースのリクエスト。ETagアプリケーションロジックにヘッダーを含めるために計算された努力をしました。

私はたまたまPHPを使用していたので、@ Mehranの(OPの)コメントが飛び出しました(彼/彼女はheader_remove()、必要なキャッシュ関連のヘッダーを送信する前に呼び出すと問題が解決すると言っています)。

率直に言って、私はこのソリューションに懐疑的でした。なぜなら、a) PHP はデフォルトで独自のヘッダーを送信しないと確信していたからです (そして、私の構成では送信しません)。b) var_dump(headers_list());PHP でカスタム キャッシング ヘッダーを設定する直前に呼び出したとき、ヘッダー セットは、意図的にすぐ上に設定していたものだけでした。

header('Content-type: application/javascript; charset=utf-8');

それで、失うものは何もないので、header_remove();カスタムヘッダーを送信する直前に呼び出してみました. そして驚いたことに、PHP はETag突然ヘッダーを送信し始めました!

2 番目の Epiphany: 応答を gzip 圧縮すると、ハッシュが変更されます

PHP でヘッダーを指定することで、Content-typeNGINX (私が使用している Web サーバー) に、PHP が応答を NGINX に返したら GZIP するように指示していました。明確にするためにContent-type、私が指定していたのは、NGINX の gzip のタイプのリストにありました。

完全を期すために、私の NGINX GZIP 設定は次のとおりであり、PHP は php-fpm を介して NGINX に接続されています。

gzip            on;
gzip_min_length 1;
gzip_proxied    expired no-cache no-store private auth;
gzip_types      text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript image/svg+xml;

gzip_vary on;

「gzippable」コンテンツタイプが指定されているときに、なぜNGINXがETagPHPで送信した. これは完全に理にかなっています。ETag生成に使用された応答と一致しない場合にを送信しても意味がありません。NGINX がこのシナリオを非常にインテリジェントに処理するのは非常に巧妙です。

NGINX が、圧縮されていないがヘッダーを含むETag応答本文を圧縮しないほど常にスマートであるかどうかはわかりませんが、それがここで起こっているようです。

更新:この点に関する NGINX の動作を説明する解説を見つけました。これは、この主題に関する 2 つの貴重な議論を引用しています。

  1. 動作について議論している NGINX フォーラム スレッド
  2. プロジェクト リポジトリでの接線方向の議論。コメントを参照してくださいPosted on Jun 15, 2013 by Massive Bird

この貴重な説明を保存するために、もしそれが消えてしまった場合、私Massive Birdは の議論への貢献から引用します:

Nginx は、オンザフライで応答を gzip するときに Etag を取り除きます。gzip されていない応答は、gzip された応答に匹敵するバイト単位ではないため、これは仕様によるものです。

ただし、この点に関するNGINXの動作は、同じ仕様であるという点でわずかに欠陥があると見なされる場合があります

... また、weak Etags (W/ で始まる Etag 値) と呼ばれるものがあり、応答が意味的に同等であるかどうかを確認するために使用できることを示しています。その場合、Nginx はそれを台無しにすべきではありません。残念ながら、そのチェックがソース ツリーに反映されることはありませんでした [悲しいことに、引用は現在スパムでいっぱいです]。」

この点に関するNGINXの現在の性質、特に「弱い」Etagsのサポートが追加されているかどうかについては不明です.

それで、解決策は何ですか?

ETagでは、応答に戻るための解決策は何ですか? PHP で gzip を実行して、NGINX が応答が既に圧縮されていることを確認し、ETagヘッダーをそのままにして単純に渡すようにします。

ob_start('ob_gzhandler');

ヘッダーと応答本文を送信する前にこの呼び出しを追加すると、PHP はETagすべての応答で値を送信し始めました。はい!

その他の教訓

以下は、私の調査から得られた興味深い情報です。この情報は、PHP であれ他の言語であれ、サーバー側のキャッシングの実装をテストする際に便利です。

Chrome とその開発者ツールの「ネット」パネルは、リクエストの開始方法によって動作が異なります。

たとえば を押すなどして、リクエストが「新しく」作成された場合Ctrl+F5、Chrome は次のヘッダーを送信します。

Cache-Control: no-cache
Pragma: no-cache

サーバーが応答します200 OK

のみでリクエストが行われた場合F5、Chrome は次のヘッダーを送信します。

Pragma: no-cache

サーバーが応答します304 Not Modified

最後に、既に表示しているページへのリンクをクリックする、Chrome のアドレス バーにフォーカスを置いて Enter キーを押すことによってリクエストが行われた場合、Chrome は次のヘッダーを送信します。

Cache-Control: no-cache
Pragma: no-cache

サーバーが応答します200 OK (from cache)

この動作は最初は少し混乱しますが、どのように機能するかがわからない場合は、理想的な動作です。これにより、考えられるすべての要求/応答シナリオを非常に徹底的にテストできるからです。

おそらく最も紛らわしいのは、実際には Chrome がキャッシュから応答を取得しているときに (応答で証明されているように)、Chrome が自動的に発信要求にヘッダーCache-Control: no-cacheとヘッダーを挿入することです。Pragma: no-cache200 OK (from cache)

この経験は私にとってかなり有益であり、他の人が将来この価値の分析を見つけてくれることを願っています.

于 2015-10-17T18:57:32.243 に答える
18

応答ヘッダーにはCache-Control: no-store, no-cache;が含まれます。これらはキャッシングを防ぎます。

must-revalidate, post-check=0, pre-check=0これらの値を削除します(保持できる/保持する必要があると思います-変更があったかどうかをサーバーに確認するようブラウザに指示します)。

そして、私は一人で固執しLast-Modifiedます(リソースへの変更がこの基準だけを使用して検出できる場合)–ETag処理がより複雑です(特にPHPスクリプトで自分で処理したい場合)、およびGoogle PageSpeed / YSlowこれに対してもアドバイスします。

于 2013-04-09T13:19:18.247 に答える