Cowboy-リクエストの生涯

リクエストの生涯

この章ではCowboyの実装の詳細と合わせてリクエストが送信されるまでに通過する順路を説明します。

リクエスト/レスポンス

皆さんご存知のようにHTTPクライアントはサーバに接続し、リソースへのリクエストを送信します。
サーバはリクエストを受け取ればリソースを含むレスポンスを返信します。

サーバがリソースを送信する前に、リクエストを読み込んで、リソースを見つけ、レスポンスを準備するために、さまざまな動きを実行する必要があり、多くの場合にはユーザが行ったことと関連する動きをログに書き込み追加することができます。

Cowboyではリクエストは次のルートを取ります。

これはデフォルトのミドルウェアの状態を表していますがあなたの環境へとセットアップされた状態によっては異なる構成へと変更することもできます。
濃い緑はあなたのコードをフックすることができるポイントを示していて、ライトグリーンは必要に応じてCowboyのコードを設定することができる部分です。

acceptor は接続を受け入れ、それを処理するためのErlangのプロセスを作成するサーバーの一部です。
parser はソケットから読み込みやソケットがクローズされるまでリクエストがくるように要求を処理します。

レスポンスはリクエストの生涯の中で多数の異なるポイントで送信することとなります。
Cowboyがリクエストを解析できない場合はエラー応答を返信し断念します。
ルータはリソースが見つからない場合は、見つからない旨をエラーで送信します。
独自のコードはもちろんレスポンスを送信することができます。

リクエストが送信されると必要に応じてリクエストを変更したり onresponse フックを有効にすることによって設定に基づいた実行を行うことができます。
デフォルトではリクエストがクライアントに直接送信されます。

その後?

動作は使用しているプロトコルに依存します。

HTTP/1.0は接続につき1つのリクエストを処理することができないため、レスポンスを送った直後にCowboyは接続を終えます。

HTTP/1.1はクライアントがサーバ接続を接続し続けるようにリクエストすることができます。
このメカニズムは次のセクションで説明しています。

SPDYは同じ接続に関して非同期で複数のリクエストを送信することを許可するように設計されています。
上記があなたのアプリケーションのために何をできるかについての詳細は、この章の後半で説明します。

Keep-alive(HTTP/1.1)

HTTP/1.1を使用すると後続のリクエストが来るまで接続が開いたままになることがあります。
このメカニズムはkeep-aliveと呼ばれています。

クライアントがサーバにリクエストを送信すると、開いたソケットを残したいかどうかを示すヘッダを含んでいます。
サーバ側は受け入れられない場合もあるためレスポンスで同じヘッダを送信することによって選択肢を示します。

CowboyはHttp/1.1リクエストの全ての応答にて自動的にこのヘッダーが含まれます。
必要に応じて、あなたはソケットの終了を強制することができます。
Cowboyは接続をするときにヘッダーの「connection: close」見ています。返事が送られると直ぐに返信がないため、接続を終えます。

このスニペットは接続を閉じることをCowboyに強制します。

{ok, Req2} = cowboy_req:reply(200, [
    {<<"connection">>, <<"close">>},
], <<"Closing the socket in 3.. 2.. 1..">>, Req).

Cowboyは同じ接続上で新しいリクエストを一定数受け入れます。
デフォルトでは100のリクエストまで実行されます。
この数はHTTPリスナーの起動時のmax_keepaliveの設定値に設定することで変更可能です。

cowboy:start_http(my_http_listener, 100, [{port, 8080}], [
        {env, [{dispatch, Dispatch}]},
        {max_keepalive, 5}
]).

Cowboyはすべてのリクエストに対して同じプロセスを再利用することで keep-aliveメカニズムを実装しています。
これはCowboyがメモリを節約するためにそうなっています。
ほとんどのコードは後続のリクエストに影響を与える任意の副作用を持っていないためうまく動作します。
しかしそれは副作用を持っているコードの場合にはクリーンアップする必要があるということです。
terminate/3 の機能は、この目的のために使用することができます。

Pipelining (HTTP/1.1)

HTTPはクライアントがリクエストを送信しサーバからのレスポンスを待つシーケンシャルプロトコルとして設計されていますが、レスポンスを待たずにサーバ
に複数のリクエストを送信ようにソケットがどのように機能するかは防げません。
サーバはリクエストを順次処理し、同じ順序でレスポンスを送信します。

このメカニズムはパイプラインと呼ばれています
クライアントから同時に多くのリソースを要求する必要がある場合には待ち時間を減少させる効果があります。
例えばブラウザが静的ファイルを要求するときに使用されています。

これはサーバによって自動的に処理されます。

非同期要求(SPDY)

SPDYではクライアントはいつでもリクエストを送信することができます。
そしてサーバもいつでもレスポンスを送信することができます。

例えば、クライアントが再びリクエストを送るために前回の送信が完全に終わりきるまで待つ必要がないことを意味します、リクエストとリクエストの間にはさみこむことができます。
同じことはレスポンスでも同様です。
レスポンスも異なる順序で送信されも問題はありません。

リクエストとレスポンスは完全に非同期であるため、Cowboyはリクエストごとに新しいプロセスを作成し、これらのプロセスは接続自体を処理する別のプロセスによって管理されます。

SPDYサーバはクライアントが要求する前にクライアントに対してリソースを送信することを決定することができます。
これは全体の応答の待ち時間を減少させ、要求されたHTMLページに関連した静的ファイルを先に送信しておけるために特に有効です。
しかしCowboyは現在の時点では、このメカニズムをサポートしていません。