PerfData

HTTPプロトコル

Webパフォーマンス入門: HTTPヘッダ

2018年4月13日
著者: Kameerath Kareem
翻訳: 小川 純平

この記事は米Catchpoint Systems社のブログ記事 Web Performance 101: HTTP Headersの翻訳です。
Spelldataは、Catchpointの日本代理店です。
この記事は、Catchpoint Systemsの許可を得て、翻訳しています。


Hypertext Transfer Protocol (HTTP) は、Tim Berners-Leeによって、1991年に初めて導入されました。
最初のバージョンであるHTTP/0.9は、クライアント・サーバ間の、データ伝送の助けとなるように設計されました。
このプロトコルは、TCP接続において、リクエスト・レスポンスモデルで動作しますが、長年にわたって改善や機能拡張が行われ、進化してきました。

最新バージョンはHTTP/2で、Webページのパフォーマンスとスピードを重視した、大きな改善が導入されています。(※)
(※ 訳注:Spelldataの検証では、HTTP/2では、Webサイトの表示速度は高速化できません。)

HTTPリクエストとレスポンス

この記事では、HTTPモデルの重要な部分 ― ヘッダについて、お話します。
先に進む前に、HTTPの動作について理解するために、こちらのブログ記事を読んで下さい

HTTPヘッダとは

リクエスト・レスポンス構造を構成する、3つの主要なコンポーネントがあります。
これは、以下の3つを含みます。

Requestヘッダ


POST / HTTP/1.1                                        ← 開始行
Host: localhost:8000
User-Agent: Mozilla/5.0 (Machintosh;… ) Firefox/51.0
Accept: text/html, application/xhtml+xml,…, */*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflat
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Content-Type: multipart/form-data; boundary=-12656974
Content-Length: 345
                                                       ← 空白行
-12656974                                              ← body部
(more data)

Responseヘッダ


HTTP/1.1 403 Forbidden                                 ← 開始行
Server: Apache
Content-Type: text/html; charset=iso-8859-1
Date: Wed, 10 Aug 2016 09:23:25 GMT
Keep-alive: timeout=5, max=1000
Connection: keep-alive
Age: 3464
Date: Wed, 10 Aug 2016 09:46:25 GMT
X-Cache-Info: caching
Content-Length: 220
                                                       ← 空白行
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML2.0//EN">      ← body部
(more data)

このHTTPメッセージの種類に基づけば、開始行はメソッド、パス、ステータスコード、プロトコルバージョンを含みます。
次の行以降はHTTPヘッダで、コロンで分けられたname-valueペアとして定義されます。
これらのヘッダは、リクエストやレスポンスと一緒に、追加のパラメータを送信するために使われます。
メッセージの本文には、リクエストの際に送信されるデータ、又はレスポンスと共に受信するデータが含まれています。

ヘッダにはいくつか種類があり、これらは利用方法で分けて、大きく分けて4つのカテゴリに分類することができます。

ヘッダの分類

ジェネラルヘッダ

リクエスト・レスポンスメッセージの両方で利用できるヘッダで、やり取りされるデータからは独立しています。
よく利用されるジェネラルヘッダとしては、

Cache-Control

Cache-Controlはジェネラルヘッダの一種で、レスポンス→リクエストの繰り返しの中における、キャッシュの設定を行うためのものです。
このディレクティブはヘッダの中で指定され、クライアント・サーバ間においてキャッシュを行う際には、厳格に実装されなければなりません。
例えば、Webページ上の静的ファイルをキャッシュするには、下記のフォーマットを用いてヘッダを定義することができます。


Cache-Control: public, max-age=31536000
Cache-Controlヘッダの定義情報一覧
Cache Request説明
max-stale[=<seconds>]クライアントは期限の切れたコンテンツでも受け入れ、秒単位でレスポンスの失効期限を設定することができます。
max-age=<seconds> リソースを最新であると見做す時間を秒数で指定します。
min-fresh=<seconds> 少なくともここで設定された秒数の間は、クライアントはレスポンスが最新 (fresh) であると見做します。
no-cache キャッシュされたコンテンツについて、サーバからクライアントに送信する前に、サーバ側で確認しなければなりません。
no-store リクエスト・レスポンスデータをキャッシュすることを禁止します。
no-transform キャッシュされたコンテンツの変換を禁止します。例えば、容量削減のため、画像形式を変換することなどです。
only-if-cached クライアントはキャッシュされたコンテンツを読み込むのみで、リクエストを送ってオリジンサーバ上の最新のコンテンツを確認したりはしません。
Cache-Controlヘッダの定義情報一覧
Cache Request説明
must-revalidate取得したリソースが古いものでないことを確認しなければなりません。
no-cache上述を参照
no-store上述を参照
no-transform上述を参照
publicプライベートキャッシュでも、共有キャッシュ(プロキシサーバにおけるキャッシュ)でもレスポンスをキャッシュします。
private個々のPC・スマートフォンなどの上でのキャッシュです。レスポンスはプライベートキャッシュに保存されますが、共有キャッシュへの保存は禁止されます。
proxy-revalidate共有キャッシュに適用されます。レスポンスが最新版であることを確認しなければなりません。
max-age=<seconds>上述を参照
s-maxage=<seconds>共有キャッシュにおける、キャッシュ有効時間。この値は、プライベートキャッシュには適用されない。

他にもいくつか、HTTPキャッシングの標準には属さないヘッダディレクティブがあります。
これはExtension Cache-Controlディレクティブと呼ばれ、例えばimmutableなどがあります。
immutableディレクティブは、レスポンスの本文が変更されていないままであることを示し、クライアントはコンテンツのバリデーションを繰り返さなくて済みます。

Connection

Connectionヘッダは、データ交換が完了した後、HTTPコネクションが開いたままになるように指定するものです。
持続的な接続をセットアップし、後に続くリクエストで再利用できるようにします。

接続を開いたままにするためには、ヘッダが次のフォーマットで送信される必要があります。


Connection: keep-alive

ヘッダディレクティブは、次のものを含みます。

Keep-alive
接続を持続的にし、一度接続が確立されると、後続の全てのリクエストが終わるまで、開いたままになります。
Close
この値は、クライアントかサーバに対し、接続を閉じるよう指示するものです。

Transfer-Encoding

Transfer-Encodingは、メッセージの本文のコンテンツを送信する際に使われるフォーマットやエンコーディングを指定するものです。
例えば、ファイルが圧縮されるように指定するには、ヘッダが次のフォーマットで送信される必要があります。


Transfer-Encoding: compress

カンマで区切って、複数のエンコーディングフォーマットを指定することもできます。
このヘッダの値に入るのは、次のディレクティブです。

chunked
クライアントやサーバに送信される前に、コンテンツをチャンクに分割します。
deflate
deflate 圧縮アルゴリズムを用いて、コンテンツを圧縮します。
gzip
Unixのgzipプログラムをベースにした、もう1つの圧縮フォーマットです。
identity
コンテンツの圧縮・変更が不要であることを示します。

リクエストヘッダ

これらのヘッダは、要求されたデータのためのパラメータ、又は、リクエストを行うクライアントについての重要な情報を提供するパラメータを定義します。
リクエストヘッダの中で、一般的なものとしては、以下のようなものがあります。

Accept-encoding

このリクエストヘッダは、クライアントがサポートするエンコーディングを指定します。
例えば、クライアントが複数のエンコーディングに対応していることを示す場合、ヘッダのフォーマットは下記のようになります。


Accept-Encoding: deflate, gzip;q=1.0, *;q=0.5

このヘッダに指定できる値は、下記の通りです。

If-match

If-matchリクエストヘッダは条件付きリクエストであることを示します。
このヘッダは、ヘッダで指定された、ETag(リソースに対してユニークな識別子)又はETagの値のリストにマッチした場合にのみ、要求されたレスポンスを返します。

例えば、以下のETagのいずれかを持つサーバからリソースを返す場合、ヘッダは次のようなフォーマットとなります。
("W/"は弱いETagの値を示し、1バイト1バイト正確に確認はしない可能性があります。)


If-Match: W/"67ab43", "54ed21", "7892dd"

If-modified-since

このヘッダも条件付きリクエストです。
サーバは、要求されたリソースが、指定された日付以降に変更されている場合にのみ、そのリソースを返します。

If-Modified-SinceはGETかHEADリクエストでしか使われることはありません。
例えば、2017年10月1日より後に変更されたリクエストを返す場合、ヘッダを次のようなフォーマットで送信します。


If-Modified-Since: Sun, 1 Oct 2017 01:28:00 GMT

リクエストヘッダは、下記の値をデータパラメータとして受け取ることができます。


If-Modified-Since: <day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT

Range

Rangeヘッダはドキュメントやリソースの一部を返すように指定します。
これは、異なる範囲に分割されたコンテンツの一部や、コンテンツの一部分のみをリクエストする際に使われます。
例えば、あるバイトとバイトの間のデータを取得する場合、ヘッダのフォーマットは、下記のようになります。


Range: bytes=200-1000, 2000-6576

1つのコンテンツの、複数の部分をリクエストしたい場合、ヘッダは下記のようなフォーマットになります。


Range: <unit>=<range-start>-<range-end>, <range-start>-<range-end>, <range-start>-<range-end>

User-Agent

User-Agentリクエストヘッダはクライアントアプリケーションに関する詳細、例えばソフトウェアのバージョン、アプリケーションタイプ、オペレーティングシステムなどを提供します。
一般的なユーザエージェントヘッダは、下記のようなフォーマットになります。


User-Agent: Mozilla/<version> (<system-information>) <platform> (<platform-details>) <extensions>

下記は、Firefoxのユーザエージェント文字列の例です。


Mozilla/5.0 (platform; rv:geckoversion) Gecko/geckotrail Firefox/firefoxversion

レスポンスヘッダ

これらのヘッダは、送信されてくるレスポンスに関する情報を含みます。
レスポンスヘッダの中で、一般的なものをいくつか、下記に示します。

Accept-Ranges

このレスポンスヘッダは、クライアントにサーバが、範囲指定のリクエストをサポートすることを知らせるものです。
値には、範囲の値の単位を指定します。
例えば、範囲リクエストがバイト単位で送信される場合、ヘッダのフォーマットは下記のようになります。


Accept-Ranges: bytes

ETag

ETagは要求されたリソースに対する一意の識別子です。
キャッシュされたリソースのバージョンを特定しやすくし、リソースの更新の経過を追いやすくします。
Webページ上の画像に対して生成されたetagは、他のレスポンスヘッダのフォーマットと共に送信されます。


ETag: "<etag_value>"

例えば、以下のような記載になります。


etag:51baf2f08d0b59d55196aba274562dcc

Location

Locationレスポンスヘッダは、ページリダイレクトを示すもので、3xxステータスコードのレスポンスと共に送信されます。
ページのリダイレクト先URLを指定します。
ヘッダのフォーマットは下記のようになります。


Location: <url>

Vary

このレスポンスヘッダはリクエストヘッダ群を指定し、キャッシュされたリソースに対する再バリデーションが求められているかを確定します。
例えば、キャッシュされたリソースのモバイルバージョンを配信するには、下記のようにVaryヘッダの値を設定し、リソース配信の前にUser-Agentヘッダを確認するようにします。


Vary: User-Agent

エンティティヘッダ

エンティティヘッダは本文を補足するコンテンツを表すものです。
エンティティヘッダとして一般的なものとしては、次のようなものがあります。

Allow

エンティティヘッダAllowは、要求されたリソースが受け付けることができる、HTTPメソッドを示すために用いられます。
例えば、以下のヘッダの値は、リソースに関連するメソッドを示しています。


Allow: GET, POST, HEAD

Content-Encoding

このエンティティヘッダは、本文で用いられているエンコーディングの種類を示します。
ヘッダは下記のフォーマットで送信されます。


Content-Encoding: gzip

1つのヘッダの中に複数のエンコーディングを含めることもできます。


Content-Encoding: deflate, gzip

Content-Length

このヘッダは、エンティティ、又はメッセージ本文のサイズを示します。
ヘッダのフォーマットは、下記のようになります。


Content-Length: <length>

例:


Content-Length: 3495

ここでは、長さはオクテット数(※)になります。
(※訳注: 8bit単位の数。Byteと同義だが、昨今1MB=1000KBのように10進数で表されることもあるのに対して、オクテットは必ず8bitとなる。)

Expires

Expiresヘッダは、リソースが最新であると考えられる日にち・時間を示します。
例えば、10月10日以降はリソースを古いものとして扱う場合、ヘッダは以下のようになります。


Expires: Wed, 21 Oct 2015 07:28:00 GMT

今回は、様々なHTTPヘッダの分類と、よく使われるヘッダをいくつかご紹介してきました。
これらのヘッダは、キャッシュや、HTTPトランザクションの保護のために必須なものです。
次回の記事では、異なる観点から、HTTPヘッダの役割についてと、ヘッダを用いた際に発生する、パフォーマンスの問題のトラブルシューティングについてお話したいと思います。