http

HTTP ツール

HTTP のステータスとリダイレクトの意味、Cache-Control ディレクティブ、ヘッダーや URL、User-Agent、OGP がおかしいときにどのツールで何をどう確かめるかまで、実務のデバッグ手順を前提にまとめた HTTP のリファレンスです。

9 ツール

§01 分野ガイド

HTTP のやり取りを4層に分けて見る

HTTP のデバッグは、URL(何を要求したか)・リクエストヘッダー(何者だと申告し何を受け取るか)・ステータス行(判定)・レスポンスヘッダー(キャッシュ・セキュリティ・Content-Type を決める契約)を分けて見ることから始まります。ボディが壊れる時点で、理由はヘッダーが語っています。

ブラウザに見える内容も origin の生の出力ではありません。間には CDN、プロキシ、HTTP/2 や /3(フィールド名は小文字化)、Service Worker、キャッシュが挟まり、200 OK (from disk cache) はレスポンスではなくその記憶です。User-Agent も偽装できる自己申告で、確実なのは origin が返すステータスとヘッダーだけです。

ステータスクラスの早見表

クラス意味クライアントの動作ヒューリスティックキャッシュ可
1xx中間応答(100101103)待ち続ける不可
2xx成功ボディを使う(204 は本文なし)200203204206
3xxリダイレクト / 再検証Location を辿る。304 はキャッシュを再利用300301308
4xx要求の内容が誤り直して送り直す。盲目的に再試行しない404405410414
5xx正しい要求にサーバーが失敗バックオフし Retry-After に従う501 のみ

右端は、Cache-ControlExpires も無いレスポンスをキャッシュが独自判断で再利用してよいコードです(RFC 9110 §15.1)。404410 も含まれるため、削除したページに no-store を付けないと「消したはずのページが消えない」ことが起こります。5xx で該当するのは 501 だけです。扱いを誤りやすいのは 429304 で、前者には Retry-After を必ず付け、後者は成功なのでエラー扱いするとキャッシュが効いている事実が障害に見えます。

リダイレクトの選択表

コード恒久性メソッドとボディ用途
301恒久保持されない(GET 化されうる)URL 改名・ホスト統合
302一時保持されない旧来の既定。POST には使わない
303一時保持されない(GET 化)POST 後に結果ページへ
307一時保持されるエンドポイントの一時移動
308恒久保持されるPOST エンドポイントの恒久移動

301 はブラウザに強くキャッシュされ、消すまで残ることもあるため取り消しが高くつきます。必ずステージングで確認してください。

Cache-Control の読み方

ディレクティブ制御対象補足
max-age=N全キャッシュの鮮度(秒)0 は毎回再検証
s-maxage=N共有キャッシュの鮮度のみCDN で max-age を上書き
no-cache保存は可、再利用前に再検証no-store と別物
no-store保存そのものを禁止認証後の HTML
private共有キャッシュに保存させない個人向け
immutable鮮度内は再検証しないハッシュ付き静的資産

Vary も同じで、Accept-Language などで内容が変わるのに宣言しなければ共有キャッシュが別バリアントを配ります。

どのツールで何を確かめるか

origin 自身の応答を見たいときは HTTPヘッダーチェッカーapi.sitekits.dev から実行するので拡張機能やキャッシュが経路に入らず、最終ステータス・最終 URL・リダイレクト回数・全ヘッダーが分かります(ヘッダーのみ取得、localhost は対象外)。

送る側を試すなら REST APIテスター。ブラウザから対象へ直接送るので対象の CORS がそのまま効き、OPTIONS でプリフライトも見られます。トークンは JWTデコーダーexp とクレームを確認(デコードは検証ではありません)。

壊れている単位が1リクエストではなくページ全体なら、DevTools の Network から HAR を書き出して HARビューアー へ。エントリがメソッド・ステータス・種別・サイズ・時間の表になり 4xx/5xx が色付きで浮くので、遅いのか落ちているのかを一画面で絞り込めます(読み方は HAR ガイド)。

疑いが URL 自体に向いたときは URLパーサー が先です。WHATWG パーサーでスキームからフラグメントまで分解し、クエリはパーセントデコード済みの表になるため、OAuth のコールバックや署名付き URL で「どのパラメータが落ちたか」がその場で分かります。値が %2520 のように壊れていれば二重エンコードなので、URLエンコード で1段ずつ戻します。

ステータスもボディも正常なのに挙動が合わないなら、疑うのは申告値か型定義です。ログの振り分けや bot 判定がずれているときは UserAgentパーサー がブラウザ・OS・デバイス種別と bot ヒューリスティックまで分解します(自己申告値なので手掛かり止まりです)。コードの意味を引くだけなら HTTPステータスコード を番号か語句で絞り込むのが速く、表示されるはずのファイルがダウンロードされる症状は MIMEチェッカー で拡張子に対応する Content-Type を確かめます。レスポンス自体は正常なのに共有カードだけ崩れるときは、ページの HTML を OGプレビュー に貼ります。取得ではなく貼り付け解析なので、ステージングビルドやログインの内側でも使えます。

つまずきやすい点

平文 HTTP に載せた HSTS は無効

HTTP 経由の Strict-Transport-Security は無視され、Secure Cookie も破棄されます。80番はリダイレクトのみ、ヘッダーは HTTPS 側に付けます。

セキュリティヘッダーはレスポンス単位

HTML の Content-Security-Policy は API の JSON や CDN のエラーページに効きません。CSPジェネレーター で組んでも、載るかはデプロイ設定次第。

リダイレクトの連鎖は往復回数を増やす

http://example.comhttps://example.comhttps://www.example.com//home/ は、HTML が1バイトも届く前に3往復を余分に消費し、しかも各ホップでメソッド・Cookie・クエリ文字列が落ちる余地があります。エッジで1ホップに畳んでください。

ボディにエラーを入れた 200 は監視をすり抜ける

{"error": ...}200 で返すとステータス基準のアラートから障害が消え、可用性が過大に見えます。SLO を持つなら本文も検査を(SRE の道具)。

+%20 は入れ替えられない

application/x-www-form-urlencoded として解釈されるクエリ文字列では + は空白にデコードされますが、パスセグメントでは文字どおりのプラス記号です。兄弟のような不具合が二重エンコードで、%20%2520 になると、エスケープではなくルーティングの問題に見えます。

FAQ
リダイレクト後に POST が GET になってしまうのはなぜですか?
301 と 302 はクライアントがメソッドを GET に書き換えてボディを捨てることを許しており、ブラウザは実際にそうします。メソッドとボディを保ったまま転送したいなら、一時移動は 307、恒久移動は 308 を使ってください。フォームや Webhook のペイロードが黙って消える障害は、http から https への昇格や末尾スラッシュの正規化を 301 で行っているのが原因のことが多いです。
DevTools で見えるレスポンスヘッダーがサーバー設定と違うのはなぜですか?
DevTools が見せているのは、すべてのホップを通過した後のレスポンスです。CDN・リバースプロキシ・Service Worker がヘッダーを追加・書き換え・削除しますし、HTTP/2 と /3 はフィールド名を小文字化して reason phrase を落とします。200 (from disk cache) と表示された行はそもそも新しいレスポンスではありません。サーバー側から取得すればこれらの変数が消え、最終 URL に対して origin が実際に返したヘッダーが分かります。
Cache-Control の no-cache を付ければブラウザに保存されなくなりますか?
なりません。no-cache は保存を許可した上で、保存済みのコピーを再利用する前に ETag と If-None-Match などで origin に再検証させるディレクティブです。ディスクへの保存自体を禁じるのは no-store です。認証後の HTML は private, no-store、ファイル名にハッシュを含む静的資産は長い max-age と immutable が定石です。
curl では成功する API がブラウザだと CORS エラーになるのはなぜですか?
CORS を強制するのはサーバーではなくブラウザで、curl は一切考慮しません。単純リクエスト以外ではブラウザが先に OPTIONS のプリフライトを送り、origin が対応する Access-Control-Allow-Origin (Cookie を伴う場合は Access-Control-Allow-Credentials も) を返さない限りレスポンスを読ませません。サーバーは 200 を正しく返しているのに、こちらが読めないだけというケースが大半です。まず OPTIONS の応答ヘッダーを確認してください。
Strict-Transport-Security を付けたのに効かないのはなぜですか?
ブラウザが HSTS を受け付けるのは HTTPS で届いた場合だけだからです。平文 HTTP のレスポンスに載せたポリシーは無条件に破棄され、そこで発行した Secure Cookie も同様に捨てられます。80番のレスポンスは HTTPS へのリダイレクトだけを返し、セキュリティヘッダーは HTTPS 側のレスポンスに付けてください。確認は最終的な 200 だけでなく各ホップで行います。チェーンの末尾にヘッダーがあることは、最初のホップが何を返したかを何も保証しません。なお includeSubDomains と preload は、公開した max-age の間すべてのサブドメインを HTTPS に縛り、preload リストからの削除には数か月かかります。