4

SimpleHTTPRequestHandler で HTTP/1.1 を使用すると、他のリソースを取り込むページをロードすると、2 番目のリソースの後でハングします。

ここに小さな再現機があります:

from SimpleHTTPServer import SimpleHTTPRequestHandler
from BaseHTTPServer import HTTPServer

class MyRequestHandler(SimpleHTTPRequestHandler):
    #protocol_version = "HTTP/1.0"   # works
    protocol_version = "HTTP/1.1"   # hangs

server = HTTPServer(("localhost", 7080), MyRequestHandler)
server.serve_forever()

上記のサーバーでは、ブラウザがロードしようとすると、次の HTML がハングしますb.png

<html>
    <body>
        <img src="a.png">
        <img src="b.png">
    </body>
</html>

SimpleHTTPServer モジュールで HTTP/1.1 を使用できますか? ForkingMixIn または ThreadingMixIn をサーバーに追加すると処理が進むようになりますが、これらの mixin がなくても可能であるように思われます。

4

1 に答える 1

7

表示される動作は、次の 3 つの理由によるものです。

  • BaseHTTPServer.HTTPServerデフォルトでは、一度に 1 つのリクエストしか処理できません
  • ほとんどのユーザー エージェント (ブラウザー) は、特定のホストに対して一度に複数の接続を開きます。
  • ほとんどのユーザー エージェントkeep-aliveは HTTP 1.1 の機能を使用し、要求されたエンティティを受け取った直後に接続を閉じません。

ご覧のとおり、ブラウザーは、サーバーに対して開いた最初の接続を使用して、要求されたすべてのエンティティを取得できます。これはページそのものであり、おそらくそのリソースの一部です。同時に、ブラウザは残りのリソースを取得するために追加の接続を開きますが、サーバーが最初の接続に関連付けられているため、これらの接続を続行できません。サーバーが最初の接続に関連付けられている理由は、ブラウザがこの接続を使用して要求されたエンティティを既に受信していても、近い将来に再利用してさらに多くのエンティティを取得できる場合に備えて、すぐに閉じないためです (サーバーは接続を閉じません)。その側は、ブラウザが HTTP のバージョン 1.1 を指定して送信したかのいずれかです。Connection: keep-aliveヘッダ)。最初の接続がタイムアウトした後にのみ、サーバーは次の待機中の接続の処理を開始するため、追加のリソースがダウンロードされます (すべてこの特定の接続を使用して要求されました)。十分に長く待つと、ブラウザはすべてのリソースを取得できます。network.http.max-persistent-connections-per-serverFirefox でプリファレンスを 1 (デフォルトの 6 ではなく) に設定した場合、または他のブラウザーで同様に設定した場合に、違いを確認できます。次に、すべてのリソースが同じ接続を使用して要求されるため、前のリソースが取得されるとすぐに各リソースの取得が遅延なく開始されます。

freenode.net の #python IRC チャンネルの marienz に、この問題について助けてもらったことに感謝します。

于 2013-04-14T18:14:19.823 に答える