Webサーバーがページを送信するときに、必要なすべてのCSS、JS、および画像を要求されずに送信しないのはなぜですか?


45

Webページに単一のCSSファイルと画像が含まれている場合、ブラウザーとサーバーがこの従来の時間のかかるルートで時間を無駄にするのはなぜですか。

  1. ブラウザは、Webページの最初のGET要求を送信し、サーバーの応答を待ちます。
  2. ブラウザはcssファイルに対して別のGET要求を送信し、サーバーの応答を待ちます。
  3. ブラウザは画像ファイルの別のGET要求を送信し、サーバーの応答を待ちます。

代わりに、この短くて直接的な時間節約のルートを使用できるのはいつですか?

  1. ブラウザはWebページのGETリクエストを送信します。
  2. Webサーバーは(index.htmlに続いてstyle.cssimage.jpgで)応答します

2
もちろん、Webページが取得されるまで、リクエストを行うことはできません。その後、HTMLが読み取られると順番にリクエストが行われます。ただし、これは一度に1つの要求のみが行われることを意味するものではありません。実際、いくつかのリクエストが行われますが、リクエスト間に依存関係がある場合があり、ページを適切に描画する前にいくつかを解決する必要があります。他の応答を処理するように見える前に、要求が満たされるとブラウザが一時停止し、各要求が1つずつ処理されているように見えることがあります。リソースを集中的に使用する傾向があるため、現実はブラウザ側により多くあります。
closetnoc

20
キャッシングについて誰も言及していないことに驚いています。そのファイルを既に持っている場合、私にそれを送る必要はありません。
コーリーオグバーン14年

2
このリストには数百もの長さがあります。実際にファイルを送信するよりも短いですが、最適なソリューションとはほど遠いです。
コーリーオグバーン14年

1
実は、私は... 100の以上のユニークなリソースを持っているWebページを訪問したことがない
アーメド

2
@AhmedElsoobky:ブラウザは、最初にページ自体を取得しないと、cached-resourcesヘッダーとして送信できるリソースを認識しません。ページを取得すると、元のページ(マルチテナントWebサイト)とは別の組織によって制御されている可能性のある別のページがキャッシュされていることをサーバーに通知する場合、プライバシーとセキュリティの悪夢にもなります。
ライライアン14年

回答:


63

簡単な答えは、「HTTPはそのために設計されていないため」です。

Tim Berners-Leeは、効率的で拡張可能なネットワークプロトコルを設計しませんでした。彼の1つの設計目標はシンプルさでした。(大学の私のネットワーキングクラスの教授は、専門家に仕事を任せるべきだと言っていました。)あなたが概説した問題は、HTTPプロトコルに関する多くの問題の1つにすぎません。元の形式:

  • プロトコルバージョンはなく、リソースのリクエストのみ
  • ヘッダーがありませんでした
  • 各リクエストには新しいTCP接続が必要でした
  • 圧縮はありませんでした

プロトコルは、これらの問題の多くに対処するために後で修正されました。

  • リクエストはバージョン管理され、リクエストは次のようになりました GET /foo.html HTTP/1.1
  • 要求と応答の両方を含むメタ情報のヘッダーが追加されました
  • 接続の再利用が許可されました Connection: keep-alive
  • 文書サイズが事前にわからない場合でも接続を再利用できるようにするため、チャンク応答が導入されました。
  • Gzip圧縮が追加されました

この時点で、後方互換性を損なうことなく、HTTPは可能な限り使用されています。

ページとそのすべてのリソースをクライアントにプッシュすることを提案する最初の人ではありません。実際、GoogleはSPDYと呼ばれるプロトコルを設計しました。

現在、ChromeとFirefoxはどちらも、サポートするサーバーに対してHTTPではなくSPDYを使用できます。SPDY Webサイトから、HTTPと比較した主な機能は次のとおりです。

  • SPDYを使用すると、クライアントとサーバーはリクエストヘッダーとレスポンスヘッダーを圧縮できます。これにより、複数のリクエストに対して同様のヘッダー(Cookieなど)が繰り返し送信される場合の帯域幅使用量が削減されます。
  • SPDYは、単一の接続で複数の同時多重化された要求を許可し、クライアントとサーバー間の往復を節約し、優先順位の低いリソースが優先順位の高い要求をブロックするのを防ぎます。
  • SPDYを使用すると、サーバーは、クライアントが要求するのを待たずに、クライアントが必要とするリソース(JavaScriptファイルやCSSファイルなど)をクライアントにアクティブにプッシュできます。

SPDYを使用するWebサイトを、それをサポートするブラウザーに提供したい場合は、そうすることができます。たとえば、Apacheにはmod_spdyがあります。

SPDYは、サーバープッシュテクノロジを備えたHTTPバージョン2の基盤となっています。


2
良い答えを知りました!Webブラウザーは本質的にシリアルであり、要求はかなり迅速に行われます。ログファイルを見ると、HTMLが解析されると、リソースの要求がかなり迅速に行われることがわかります。それが現実さ。悪いシステムではなく、コード/リソースの効率もそうではありません。
closetnoc 14年

6
記録のためだけに、SPDYは聖杯ではありません。いくつかのことはうまくいきますが、他の問題が発生します。ここで agains SPDYを話すいくつかのポイントを含む1品です。
2014年

3
これに興味のある方は@Jostのリンクの批判を読むことを強くお勧めします。これにより、非常に一般的に実装されていることを段階的に改善するだけでなく、誰もが使い始めるほど改善する方法を見つけるのに伴う複雑さのヒントが得られます。ユースケースの比較的大きなサブセットに対して物事をいくらか改善する改善を考えるのは簡単です。誰もが新しいプロトコルの使用を開始するような方法で物事を改善することは、変更のコストに見合うほど優れているため、まったく別の問題であり、簡単ではありません。
msouth 14年

11
彼は仕事を専門家に任せるべきだった。もし彼がそれをやったなら、彼らはそれが出てきた日に時代遅れだったであろう標準を思い付くのに6年かかったでしょう。また、専門家は誰かの許可を必要としていましたか?なぜ彼らは自分でやらなかったのですか?
シャントヌティワリ14

2
率直に言って、当時資格のある専門家はいません。誰もウェブを構築したことがないため、ワールドワイドウェブを構築する方法は誰も知りません。ハイパーメディアの概念はティムによって発明されたのではなく、CERNでの「情報の損失」の問題を解決するための「情報管理」の提案を書く10年前に、彼はさまざまなローカルハイパーメディアシステムで経験しました。
ライライアン14年

14

Webブラウザーは、サーバーからWebページ(HTML)をダウンロードするまで追加リソースを認識しません。サーバーには、それらのリソースへのリンクが含まれています。

あなたは疑問に思うかもしれません、なぜサーバーはそれ自身のHTMLを解析し、Webページの最初のリクエスト中にすべての追加リソースをWebブラウザーに送信しないのですか?これは、リソースが複数のサーバーに分散している可能性があり、Webブラウザーが既にそれらの一部をキャッシュしている、またはそれらをサポートしていないため、それらのすべてのリソースを必要としないためです。

Webブラウザーはリソースのキャッシュを保持するため、リソースをホストするサーバーから同じリソースを何度もダウンロードする必要はありません。すべてが同じjQueryライブラリを使用するWebサイト上の異なるページをナビゲートする場合、毎回そのライブラリをダウンロードするのは望ましくなく、最初のときだけです。

そのため、WebブラウザーはサーバーからWebページを取得すると、キャッシュにまだないリンクリソースを確認し、それらのリソースに対して追加のHTTP要求を行います。非常にシンプルで、非常に柔軟で拡張可能です。

通常、Webブラウザーは2つのHTTP要求を並行して作成できます。これはAJAXとは異なります-それらは両方ともWebページを読み込むための非同期メソッドです-非同期ファイルの読み込みと非同期コンテンツの読み込み。でキープアライブ、我々は一つの接続を使用して、いくつかの要求を行うことができ、かつでパイプライン我々は応答を待たずに、いくつかの要求を行うことができます。ほとんどのオーバーヘッドは通常、TCP接続のオープン/クローズに起因するため、これらの手法は両方とも非常に高速です。

生き続ける

パイプライン処理

ウェブ履歴の一部...

Webページはプレーンテキストの電子メールとして始まり、コンピューターシステムはこの考えに基づいて設計され、やや自由なコミュニケーションプラットフォームを形成しました。Webサーバーは当時のままでした。後に、画像、スタイル、スクリプトなどの追加のMIMEタイプの形式で、「電子メール仕様」にレイヤーが追加されました。結局、MIMEはMulti-Purpose Internet Mail Extensionの略です。遅かれ早かれ、本質的にマルチメディアメール通信、標準化されたWebサーバー、およびWebページができました。

HTTPでは、データは電子メールのようなメッセージのコンテキストで送信される必要がありますが、ほとんどの場合、データは実際には電子メールではありません。

このような技術が進化するにつれて、開発者が既存のソフトウェアを破壊することなく、新しい機能を段階的に組み込むことができるようにする必要があります。たとえば、新しいMIMEタイプが仕様に追加された場合(たとえばJPEG)、WebサーバーとWebブラウザーがそれを実装するのに時間がかかります。突然JPEGを仕様に強制してすべてのWebブラウザーに送信し始めるのではなく、Webブラウザーがサポートするリソースを要求できるようにするため、誰もが満足してテクノロジーを前進させることができます。スクリーンリーダーはWebページ上のすべてのJPEGを必要としますか?おそらくない。お使いのデバイスがJavascriptをサポートしていない場合、Javascriptファイルの束を強制的にダウンロードする必要がありますか?おそらくない。Googlebotは、サイトのインデックスを適切に作成するために、すべてのJavascriptファイルをダウンロードする必要がありますか?いや。

ソース:Node.jsのようなイベントベースのWebサーバーを開発しました。Rapid Serverと呼ばれます

参照:

参考文献:


まあ、実際には、これらすべての副次的な問題(キャッシュ、Content-Typeヘッダーなど)を処理できます。これらの問題を解決する回避策があります。上記の投稿のコメントで提案したように、次のようなヘッダーを使用できます> Cached-Resources:image.jpg; style.css; キャッシュの問題を解決するために..(時間があれば、上記のコメント
Ahmed 14年

はい、その考えは以前に思いついていましたが、HTTPのオーバーヘッドが大きすぎるため、リソースが複数のサーバーに分散しているという事実を解決できません。さらに、あなたが提案した時間節約方法は、データがどのように見えてもストリームとして送信されるため、実際に時間を節約するとは思わず、キープアライブでは、100の同時HTTP要求が本質的に1つの要求になります。あなたが提案する技術と能力は、ある意味ですでに存在しているようです。参照en.wikipedia.org/wiki/HTTP_persistent_connection
ペリー

@perry:https://認証する必要があるが秘密にしない大規模な公に配布されたファイルを送信するための代替案の考えをどう思いますか?データペイロードの署名またはハッシュのいずれかを含め、ブラウザーは受信したデータをヘッダーに対して検証しますか?このような設計は、SSLハンドシェイクの手順を保存するだけでなく、キャッシュプロキシをより重要に許可します。SSLリンク経由でURLを取得すると、どこからでもデータをフィードできます。
supercat

11

彼らはそれらのリソースが何であるか知らないからです。Webページに必要なアセットはHTMLにコード化されています。パーサーがそれらのアセットが何であるかを決定した後にのみ、ユーザーエージェントはyを要求できます。

さらに、これらのアセットがわかったら、適切なヘッダー(つまりコンテンツタイプ)を提供できるように個別に提供する必要があるため、ユーザーエージェントはその処理方法を知ることができます。


2
特にrequire.jsのようなものを使用する場合。ブラウザは必要なものだけを要求します。...すべてを一度にロードすべてに想像
アランマルホランド

2
これは正しい答えであり、コメンターのほとんどが欠落していると思われるものです-サーバーがリソースを積極的に送信するには、それらが何であるかを知る必要があります。つまり、サーバーはHTMLを解析する必要があります。

1
しかし、質問は、クライアントがリソースを同時に要求できない理由ではなく、Web サーバーがリソースを送信しない理由を尋ねます。サーバーがすべて一緒に送信される関連アセットのパッケージを持ち、HTMLの解析に依存せずにパッケージを構築する世界を想像するのは非常に簡単です。
デビッドマイスター14年

@DavidMeisterサーバーはクライアントが何を望んでいるのかを常に把握していないため、検索エンジンのWebクローラーはCSS / JSを気にかけない可能性があり、ドキュメント内にそれら以外の多くのリソースがリンクされているため、 RSSをパッケージ内のWebブラウザーにフィードします(ほとんどのコンテンツはおそらく既にHTMLにあります)が、フィードリーダー<head>はRSS代替リンクを探している要素を解析するだけで、それを見つけることができます-クライアントは何に興味があるのか​​、それから何が利用可能かを知る必要があり、私たちは最初に戻ってきた
ザーフ-ベンデュグイド

@ Zhaph-BenDuguid私は別の世界について話していますが、答えはプロトコルが他の何かとどのように機能するかに関係していることを強調するためです。さらに、不要な場合でも、サーバーがすべてのデータを一度に送信する方が速い場合があります。基本的に、遅延の問題と帯域幅の使用量をトレードオフします。
デビッドマイスター

8

あなたの例では、クライアントがすでに持っているかどうかにかかわらず、Webサーバーは常に CSSと画像を送信し、帯域幅を大幅に浪費します(したがって、おそらくあなたの意図であった待ち時間を短縮して接続を遅くするのではなく、接続を遅くします)。CSS、JavaScript、および画像ファイルは通常、まさにその理由で非常に長い有効期限で送信されることに注意してください(それらを変更する必要がある場合は、ファイル名を変更するだけで、新しいキャッシュが再びキャッシュされます)。

これで、「OK、ただしクライアントは既にそのリソースの一部を持っていると示すことができるので、サーバーはそれを再び送信しない」と言うことで、帯域幅の浪費を回避することができます。何かのようなもの:

GET /index.html HTTP/1.1
Host: www.example.com
If-None-Match: "686897696a7c876b7e"
Connection: Keep-Alive

GET /style.css HTTP/1.1
Host: www.example.com
If-None-Match: "70b26618ce2c246c71"

GET /image.png HTTP/1.1
Host: www.example.com
If-None-Match: "16d5b7c2e50e571a46"

そして、変更されていないファイルのみを取得し、1つのTCP接続を介して送信します(持続接続を介したHTTPパイプライン化を使用)。そして何を推測しますか?すでに動作している方法です(If-None-Matchの代わりにIf- Modified-Sinceを使用することもできます)。


ただし、(元のリクエストのように)大量の帯域幅を浪費して遅延を本当に削減したい場合は、Webサイトを設計するときに標準のHTTP / 1.1を使用して今日できます。ほとんどの人がそれをしない理由は、それが価値があるとは思わないからです。

それを行うには、CSSまたはJavaScriptを別のファイルに入れる必要はありません。<style>また、<script>タグを使用してメインHTMLファイルに含めることができます(おそらく手動で行う必要はありません。テンプレートエンジンはおそらく自動的に行うことができます) 。次のように、データURIを使用してHTMLファイルに画像を含めることもできます。

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==" alt="Red dot" />

もちろん、base64エンコードは帯域幅の使用量をわずかに増加させますが、帯域幅の浪費を気にしないのであれば、それは問題になりません。

さて、あなたが本当に気にかけているなら、あなたは両方の世界の最高を得るためにあなたのウェブスクリプトを十分にスマートにすることさえできます:最初のリクエスト(ユーザーはクッキーを持っていません)で、ただ一つのHTMLに埋め込まれたすべて(CSS、JavaScript、画像)を送信します上記のようにファイルを作成し、ファイルの外部コピーにrel = "prefetch"タグのリンクを追加し、Cookieを追加します。ユーザーが既にCookieを持っている場合(たとえば、以前に訪問したことがある場合)、通常のHTMLのみを送信します<img src="example.jpg"><link rel="stylesheet" type="text/css" href="style.css">など)。

したがって、最初にアクセスすると、ブラウザーは1つのHTMLファイルのみを要求し、すべてを取得して表示します。次に、指定された外部CSS、JS、イメージを(アイドル状態のときに)プリロードします。次回ユーザーがアクセスしたとき、ブラウザーは変更されたリソース(おそらく新しいHTML)のみを要求して取得します。

Webサイトで何百回クリックした場合でも、追加のCSS + JS + imagesデータは2回しか送信されません。提案されたソリューションが示唆した数百回よりもはるかに優れています。そして、それ以上の使用(ない最初の時間に、また次の回に)だろう1レイテンシの増加往復。

今、それがあまりにも多くの仕事のように聞こえ、SPDYのような別のプロトコルを使いたくない場合、Apacheのmod_pagespeedのようなモジュールが既にあります。それはあなたのためにその仕事のいくつかを自動的に行うことができます(複数のCSS / JSファイルをマージします) Webページの1行を変更することなく、小さなCSSを自動的にインライン化し、それらを縮小し、オリジナルの読み込み、画像の遅延読み込みなどを待つ間に小さなプレースホルダーのインライン画像を作成します。


3
私はこれがあると思い正解。
el.pescado 14年

7

HTTP2はSPDYに基づいており、まさにあなたが提案することを行います:

高レベルで、HTTP / 2:

  • テキストではなくバイナリです
  • 順序付けられてブロックするのではなく、完全に多重化されている
  • したがって、並列処理に1つの接続を使用できます
  • ヘッダー圧縮を使用してオーバーヘッドを削減します
  • サーバーがクライアントキャッシュにプロアクティブに応答を「プッシュ」できるようにします

もっと上で利用可能であるHTTP 2よくある質問


3

これらのものが実際に必要であると仮定しないので

このプロトコルは、特定の種類のファイルまたはユーザーエージェントに対する特別な処理を定義しません。たとえば、HTMLファイルとPNG画像の違いはわかりません。あなたが求めていることをするために、Webサーバーはファイルタイプを識別し、それを解析して、それが参照している他のファイルを見つけ、次に、他のファイルが実際に必要であるかを決定する必要がありますファイル。これには3つの大きな問題があります。

最初の問題は、サーバー側でファイルタイプを識別するための標準的で堅牢な方法がないことです。HTTPはContent-Typeメカニズムを介して管理しますが、それはサーバーに役立ちません。サーバーはこのようなものを独自に把握する必要があります(一部はContent-Typeに何を入れるかを知るため)。ファイル名拡張子は広くサポートされていますが、悪意のある目的のために、脆弱で簡単にだまされることがあります。ファイルシステムのメタデータは脆弱ではありませんが、ほとんどのシステムはメタデータをあまりサポートしていないため、サーバーも気にしません。コンテンツスニッフィング(一部のブラウザーとUnix fileコマンドが実行しようとする)は、喜んで高価にしたい場合は堅牢になりますが、堅牢なスニッフィングはサーバー側で実用するには高すぎます。

2番目の問題は、ファイルの解析にコストがかかり、計算量が多いことです。これは、コンテンツを堅牢にスニッフィングする場合、さまざまな潜在的な方法でファイルを解析する必要があるという点で、最初のものと多少結びついていますが、ファイルタイプを特定した後にも適用されます参照が何であるかを把握します。これは、ブラウザーのように一度に数個のファイルしか実行しない場合はそれほど悪くはありませんが、Webサーバーは一度に数百または数千の要求を処理する必要があります。これは合計されますが、それが大きすぎると、実際には複数の要求よりも遅くなります。Slashdotまたは同様のサイトからリンクを訪れたことがありますが、使用率が高いためにサーバーがひどく遅いことを確認するためだけに、この原則が実際に動作しているのを見てきました。

3番目の問題は、サーバーがファイルをどうするつもりなのかを知る方法がないことです。ブラウザーは、HTMLで参照されるファイルを必要とする場合がありますが、ファイルが実行されている正確なコンテキストに応じて、必要とされない場合があります。それは十分に複雑ですが、Webには単なるブラウザ以上のものがあります。スパイダー、フィードアグリゲーター、ページスクレイピングマッシュアップの間には、HTMLで参照されるファイルを必要としない多くの種類のユーザーエージェントがあります。 HTML自体のみに注意してください。これらの他のファイルをそのようなユーザーエージェントに送信すると、帯域幅が浪費されるだけです。

肝心なのは、サーバー側でこれらの依存関係を把握することは、それが価値がある以上の問題だということです。その代わりに、クライアントが必要なものを把握できるようにします。


新しいプロトコルを開発するか、既存のプロトコルを修正する場合、これらの問題を何らかの方法で処理できます。また、Webサーバーはファイルを1回だけ解析し、定義済みのルールに基づいてファイルを分類できるため、最初に送信するファイルに優先順位を付けることができます。など。Webサーバーは、私が意図していることを知る必要がありません。これらのファイルでは、送信する内容、実行するタイミング、およびどのルールに依存するかを知る必要があります。(Webボットとスパイダーは問題ではありません。動作はそれらによって異なります-それらは一意のユーザーエージェントヘッダーを持ちます- ..)
アーメド14年

@AhmedElsobky:あなたが話していることは、ネットワークプロトコルというよりも特定の実装のように聞こえます。しかし、何を送信するかを決定する前に、ファイルをどうするつもりなのかを実際に知る必要があります。そうしないと、多くのユーザーが望まないファイルを送信することが避けられません。User-Agent文字列は信頼できないため、それらを使用してユーザーの意図を判断することはできません。
スプーニエスト14年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.