開発者のためのHTTP基礎

この記事は約14分で読めます。
sponsored link

HTTPって何だっけ?

HTTP (HyperText Transfer Protocol) は「システムやWEBサイト間の通信手順(ルール) 」のことです。

今回は私が気に入った海外サイトの翻訳版 (+α) として、HTTPの理解を深めていきたいと思います。

▼元ネタ (作者から編集・翻訳許可いただいてます)
HTTP: The Protocol Every Web Developer Must Know – Part 1
HTTP: The Protocol Every Web Developer Must Know – Part 2

HTTPの基礎

HTTPは ホスト/クライアント間 の通信を可能にし、様々なネットワーク機器に対応しています。

ステートレス (行きの設定をすると戻りは自動で設定されるしくみ) で、TCP/IPという通信方式が用いられます。デフォルトのポート番号は 80 (TCP/IP) ですが、もちろん他の通信方式を採用することも可能です。

ホスト/クライアント間 の通信は「リクエスト/レスポンスのペア」によって行われます。まず クライアントPC から HTTPリクエストを送信し、WEBサーバー からHTTPレスポンスが返ってくるという仕組みです。

※ ユーザーPCから閲覧した情報をURLなどでリクエストし、サーバーが内部に保持しているデータを提供します。

HTTPリクエスト

まずは、ブラウザからサーバーへ送信する「HTTPリクエスト」を説明します。

HTTPリクエストは「①リクエストライン, ②ヘッダー, ③データ本体」からなり、サーバーは受け取ったリクエストからどんな情報を返すかを判断します。

名前 詳細
リクエストライン メソッド (ほとんどの場合 “GET” ), URL, HTTPのバージョン (最新はHTTP/3)
ヘッダー User-Agent (ブラウザの種類 / OS), Referer, Cache, Cookie, Language, Encodingなど。
データ本体 HTML, 画像データなど。

HTTPレスポンス

次に、サーバーからブラウザへ送信する「HTTPレスポンス」を説明します。

HTTPレスポンスは、①ステータスコード・②ヘッダー・③データ本体 の3つで構成されており、ユーザーの画面に表示されるための情報を処理します。

名前 詳細
ステータスコード 3桁の数字 (404や200など)。詳しくは後述。
ヘッダー Content-Type, Expires, Last-Modified, Cache, Connection, Locationなど。
データ本体 HTML, 画像データなど。

URL

WEB上で行われる通信の中核となるのが、皆さんお馴染みの URL (Unified Resource Locators) です。

URLは、通信手順を決めるプロトコル、WEBサーバーを特定するドメイン名、WEBサーバーへのゲートを示すポート、リソースへのパス、引数を示すパラメーターで構成されています。

HTTPメソッド

HTTPメソッドとは「クライアントがサーバーにしてほしいことを指定するもの」です。

名前 詳細
GET 既存リソースの取得。WEBページのHTML, 画像データ, CSSファイルなど。
POST 新規リソースの作成。Twitterでの発言, 新着ブログ記事など。
PUT 既存リソースの更新。SNSのコメント編集, ブログ記事の更新など。
DELETE 既存リソースの削除。

ステータスコード

クライアント側からサーバー側へリクエスト (URL + HTTPメソッド) を送信すると、サーバーから「ステータスコード」と 付加情報 が送信されます。

ステータスコードはサーバーの応答をクライアントに伝える重要な役割です。

大分類 ステータス 詳細
100番台 (情報) 100 その時点まで問題がないので処理を継続してよい。
200番台 (成功)
200 リクエスト成功。
202 リクエスト受理。実行はまだされていない。バッチなどの非同期処理向け。
204 コンテンツなし。
205 リクエストした文章などをリセットするよう指示。
206 一部のコンテンツのみを含む。
300番台 (リダイレクション)
301 URLを新しいものへ変更。
303 リソースが一時的に新しいURLに配置されている。
304 レスポンスの変更なし。キャッシュ用に使われる。
400番台 (クライアントエラー)
400 リクエストの構文が無効。
401 未認証。Authorizationヘッダーを確認する。
403 アクセス権なし。
404 リソース無し。サーバー側がリソースを隠すために使われることもある。
405 無効なメソッド。
500番台 (サーバーエラー)
501 メソッドをサーバーが理解できていない。
503 サーバーダウン。メンテナンスや過負荷の状態など。

リクエスト / レスポンスの型


ここまで URL, HTTPメソッド, ステータスコード などHTTPの基礎的な要素をみてきましたが、ここからはそれら「メッセージの中身」について簡単に紹介します。

※ HTML/1.1以前のプロトコルでは以下のメッセージが直接送信されますが、HTML/2以降ではメッセージがHTMLフレームに分割され最適化されます。

HTTPリクエスト
GET /articles/http-basics HTTP/1.1  #1行目:リクエストライン (メソッド + URI + HTMLバージョン) 
Host: www.yonaha.info               #2行目以降:ヘッダー (リクエスト情報や属性など)
Connection: keep-alive
Cache-Control: no-cache
Pragma: no-cache
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
HTTPレスポンス
HTTP/1.1 200 OK                         #1行目:ステータスライン (HTMLバージョン + ステータス)
Date: Wed, 7 April 2021 12:00:00 JST    #2行目以降:ヘッダー (レスポンス情報や属性など)
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Server: nginx
ETag: W/"etag_value"
# 以下略

HTTPトラフィック閲覧ツール

例えば Chrome/Webkit inspector を使うと、以下のようなキャプチャを取得することができます。

またWEBアプリ用のデバッグツールとしては、Windowsで利用される Fiddler、Macで利用される Charles Proxy などが挙げられます。

主な使用用途は「HTTPリクエスト/レスポンスの監視や変更通信速度のシミュレーション」です。

WEBフレームワーク/ライブラリでのHTTP利用

次はWEBフレームワーク/ライブラリについて簡単に紹介したいと思います。

WEBフレームワークでは「HTTPリクエスト/レスポンスの直接操作」が可能で、ライブラリは「予め用意されている開発に必要な道具の集まり」です。具体例としては、ExpressJS, Ruby on Rails, jQuery Ajax などがあります。

<例>
「ExpressJS」:Node.jsのWEB開発フレームワーク。
「Ruby on Rails」:RubyのWEB開発フレームワーク。
「jQuery Ajax」:JavaScriptを使った非同期処理を実現。

HTTPの具体的な仕組み

HTTP通信

クライアントとサーバーが通信を行うには、確実に通信を行うための TCPプロトコル が求められます。(HTTPのポート番号はデフォルトで 80 )

TCP は「送受信を行う機器間で通信の開始/終了を確認する」という役割です。通信を細かく区切った TCPストリーム がIPパケットに詰め込まれ、常に正しい順序で確実にデータを届けます。

HTTPS はより安全なバージョンのHTTPで、HTTPとTCPの間に SSLTLS という層を追加したものです。(HTTPSのポート番号はデフォルトで 443 )

HTTP通信は「送信元IP, 送信元ポート」「送信先IP, 送信先ポート」によって確立され、2つのエンドポイント間の通信は以下のような複数の手順で構成されています。

① DNSによる名前解決(ドメイン名 www.yonaha.info を IPアドレス 153.246.140.229 に変換)
② サーバーとの接続を確立
③ リクエスト送信
④ レスポンス待ち
⑤ 接続終了

HTTP/1.0において、通信中のデータのやりとりは1つずつ個別に行われます。そのためクライアントが3つの異なる画像を同一サーバーにリクエストした場合、3回ホストにリクエストすることになります。しかし上図を見て分かる通り、複数回リクエストするとネットワーク上で遅延が生じてしまうのです。

この通信上の遅延を減少させるために「継続的な接続」という、クライアントが通信を終える前に新たな通信を開始するという仕組みが導入されました。HTTP/1.1ではこれがデフォルトで設定されており、通信を終える場合にはクライアントが “接続終了” を手動で知らせるという仕組みになりました。

さらにブラウザ/クライアントで遅延を減少させるために導入されたのが「並列接続」です。これまでの並列通信はデータを一時的にため込む技術が使われていたのですが、クライアントが複数のアセットを作成できるようになったことで、通信の遅延が劇的に改善されました。

継続的な接続 と 並列接続 という2つが組み合わされることにより、現在のような低遅延でなめらかなインターネット接続ができるようになったのです。

サーバー側の応答

サーバーはリクエストを受信した際に、その後の通信や処理を考えなければなりません。具体的な流れは以下の通りです。

① ポート上でソケット(入り口) を確立
② メッセージを受信し、内容を解析
③ レスポンスを処理
④ レスポンスヘッダーの設定
⑤ クライアントへ設定したレスポンスを送信
⑥ ヘッダーに”通信終了”の印があればそこで終了

ユーザー識別

サーバーは誰がどんなリクエストを送ったのか、そしてそれは許可して良いものなのかを識別する必要があります。これらの情報を集める方法はいくつかありますが、ほとんどの場合以下のアプローチを組み合わせています。

名前 詳細
リクエストヘッダー User-Agent (ブラウザの種類 / OS), Referer, Cache, Cookie, Language, Encodingなど。
クライアントIP クライアントのIPアドレス。
Fat Urls ユーザー毎に変更されるURL。クリック毎にリダイレクトされたりする。
Cookies ユーザーを識別する情報。自動ログインなどで利用。

Cookiesは “Set-Cookie” をレスポンスヘッダーで設定することで利用できます。

Set-Cookie: session-id=12345ABC; username=nettuts

またサーバーはCookieを ドメイン/パス に限定したり、”expires”値を使うことでCookieを保持したりすることも可能です。Cookieはブラウザからサーバーにリクエストを要求する際に自動で送信され、ブラウザや ドメイン/パス でそのCookieが一意のものであることを保証しています。

ユーザー認証

HTTPは初期の段階として「ベーシック認証」「ダイジェスト認証」をサポートしています。

ベーシック認証ではサーバー側が “WWW-Authenticate”レスポンスヘッダー や “401 未認証” で、クライアントのリクエストを拒否します。このヘッダー情報をみて、ブラウザがログイン画面やID/PWを表示するのです。

これらの情報は “Authentication”リクエストヘッダー内で base-64形式 でエンコードされ、サーバーがクライアントの妥当性を判断します。(追加認証の詳細が記された “Authentication-Info” を送信するサーバーもあります)

ベーシック認証の流れでできたのが「プロキシ認証」です。WEBサーバーの代わりに、クライアントとサーバーの中間にいるプロキシにリクエストを送信します。

そのプロキシは “Proxy-Athenticate”ヘッダー を “407 未認証” というステータスコードと合わせて送信し、そのヘッダー経由でクライアントに証明書が送信されるという仕組みです。

ダイジェスト認証は、ベーシック認証よりも安全なハッシュ関数を ID/PW で暗号化します。(一般的には MD5 や KDダイジェスト関数) 

ただベーシック認証の方がシンプルなため、多くのWEBサイトではベーシック認証が採用されています。安全性を考慮する場合は、ベーシック認証とSSLが組み合わせて利用するのが一般的です。

安全なHTTP

HTTPSプロトコルはWEB上での安全な通信を実現します。WEBサイトのURLの先頭が「https」となっているかどうかで、HTTPSプロトコルが使われていることを確認できます。(弊サイト yonaha.info は安全です)

HTTPSは、HTTPとTCPの間に Secure Sockets Layer (SSL) と Transport Layer Security (TLS) を挿入したものです。SSLはRSAや公開鍵を用いた強力な暗号化で、公開鍵暗号基盤 (PKI) が長期間採用されています。

HTTPSを利用するにあたり、クライアントやサーバーが送信方法を設定し直す必要はないのですが、デジタル証明書をサーバーに適用させる必要があります。

証明書

証明書は Certificate Authority (CA) によって発行され、WEB上でのユーザーを保証するという役割です。(PKIはCAsによって管理されています)

最も一般的な証明書は X.509 v3 standard で、以下のような情報が含まれています。

・証明書の発行者
・証明書に使われているアルゴリズム
・証明書を作成した人や組織
・公開鍵情報
・詳細な署名アルゴリズムを用いた署名証明書

クライアントがHTTPSでリクエストを送信する場合、まず証明書をリクエスト先のサーバーへ配置することを試みます。その証明書がサーバー上にあれば、それがCAsのリストにあるかを確認し、なければユーザーの画面に警告文が表示されるという仕組みです。

一度証明書が正しいとされれば、SSL化が完了し安全に通信することができます。

HTTPキャッシング

HTTPキャッシングは「コンテンツを専用のサーバーに蓄積させるプロセス」でネットワーク上の遅延や帯域にしばられず快適なWEB環境を実現します。

キャッシュはブラウザと元のサーバーの中間に存在し、それがどこにあるかで以下のようにカテゴライズされます。

名前 詳細
プライベート ブラウザ内にあるユーザー固有のキャッシュ。ID, PW, URL, 閲覧履歴などが保持される。
パブリック キャッシングプロキシに配置されるもの。複数のユーザーに利用されるため大きめの規模。

キャッシュプロセス

キャッシュの配置場所によらず、キャッシュプロセスはほとんど同じです。

① リクエストの受信
② URL/ヘッダーの解析
③ ローカルコピーの参照 (または貯蔵庫からの取り出し)
④ キャッシュされたコンテンツが最新のものかを確認 (必要に応じて更新) 
⑤ キャッシュのボディーと更新済みヘッダーからレスポンスを作成
⑥ クライアントにレスポンスを送信
⑦ (任意で) やりとりの内容を記録

もちろんキャッシュされた情報は常に最新のものとは限りません。サーバーはドキュメントが変更されていないのであれば “304 変更なし” を返し、キャッシュされたコピーの有効期限が切れているのであれば “200 成功” を返す新たなヘッダーを作成すべきです。

またドキュメントが削除されていれば “404 該当なし” が返ってきます。これらのレスポンスは正しいキャッシュを返し、古いコンテンツを更新するために必要なものなのです。

ドキュメント期限

キャッシュされたコンテンツが最新のものにするために、HTTPで ドキュメント期限 を設定する必要があります。

元のサーバーが有効期限をそれぞれのドキュメントに添付できるようにするのが、HTTPの “Cash-Control” と “Expires”レスポンスヘッダー です。キャッシュはこの有効期限の範囲内でドキュメントのコピーを返し、有効期限が切れるとキャッシュがサーバーに情報を確認しにいきコンテンツを更新します。

サーバー再確認

ここでいうサーバー再確認とは、キャッシュされたドキュメントの有効期限が切れた際に、最新のコンテンツをサーバー側に確認することを指します。更新頻度の高いコンテンツを扱う際には、有効期限を短くしサーバーへのアクセス頻度を増やすことが可能です。

キャッシュを取得・保持することで、クライアントが都度サーバーにクエリを発行する必要がなくなり、帯域、時間、ネットワークトラフィックなどを抑えることができます。

Reference

https://webtan.impress.co.jp/e/2010/01/12/7156
https://developer.mozilla.org/ja/docs/Learn/Common_questions/What_is_a_URL
https://tsuyopon.xyz/2019/01/31/understand-4-http-methods/#Web4HTTP
https://developer.mozilla.org/ja/docs/Web/HTTP/Status
https://qiita.com/Sekky0905/items/dff3d0da059d6f5bfabf
https://qiita.com/koheiyamaguchi0203/items/5777c4653a01ae4c7b06#httpリクエスト