本番環境でリダイレクトとHTTPヘッダーをデバッグするための小さなツールキット
クライアントとサーバーの間で実際に何が起きているかを示す、5つのコマンドラインツールとブラウザーの手法
目次
本番環境でHTTPをデバッグする難しさ
ほとんどのHTTPの問題は、ブラウザー上では見えません。リダイレクトチェーンが静かに失敗する、キャッシュヘッダーが1文字だけ間違っている、CORSポリシーが理由を示さずリクエストをブロックする。ブラウザーの開発者ツールはやり取りの結果を見せてくれますが、問題の原因になった生の通信は隠れてしまうことがよくあります。
これは本番環境で特に重要です。本番環境では、何が変わったのかを確認するためにログを追加したり、サービスを再起動したりできないからです。必要なのは、実際のHTTPのやり取りを見せてくれるツールです。リクエストヘッダー、レスポンスヘッダー、ステータスコード、リダイレクト先、タイミング。ここでは、その役割を確実に果たす5つのツールと、それらを補完するブラウザーの手法を紹介します。
curl: 基礎となるツール
curl は最初に使うべきツールです。ブラウザーによる解釈を挟まず、サーバーが送った内容をそのまま確認できるからです。
本文なしでレスポンスヘッダーを見るには:
curl -I https://example.com
リダイレクトをたどり、各ステップを見るには:
curl -L -v https://example.com
-v フラグ(verbose)は、すべてのヘッダーを含むリクエストとレスポンス全体を表示します。-L フラグはリダイレクトを自動的にたどります。この2つを組み合わせると、リダイレクトチェーン全体が見えます。本番環境の問題の多くは、ここにあります。
リダイレクト先だけを見るには:
curl -s -o /dev/null -w "%{http_code} %{redirect_url}\n" -L https://example.com
これは、完全なヘッダーのノイズなしにリダイレクトチェーンを検証したいときに便利です。-w フラグは出力を整形し、ステータスコードとチェーン内の次のURLだけを表示します。
curl ではカスタムヘッダーも送信できます。これは、CDNの挙動、認証、APIエンドポイントのテストに不可欠です:
curl -H "Authorization: Bearer token" -H "Accept: application/json" https://api.example.com
httpie: より扱いやすいデフォルトを備えたcurl
httpie はPython製のツールで、curl と同じことができますが、構文は覚えやすく、出力も読みやすくなっています。置き換えではありません。curl のほうが強力で、より広くインストールされています。ただし、素早い確認には httpie のほうが速く使えます。
ヘッダーを見るには:
http HEAD https://example.com
リダイレクトをたどるには:
http --follow --all https://example.com
--all フラグは、最終レスポンスだけでなく、リダイレクトチェーン内のすべてのレスポンスを表示します。これは curl -L -v に相当しますが、出力が色分けされていて追いやすくなっています。
JSONを送るには:
http POST https://api.example.com name=value
httpie はデフォルトでJSONを想定するため、APIをテストするときの入力が少なくて済みます。また、レスポンスを整形して表示するので、不正なヘッダーや予期しない値を見つけやすくなります。
Browser DevTools: Networkタブ
問題がブラウザーでしか起きない場合は、まずブラウザーのNetworkタブを見るべきです。curl と同じ情報を確認できますが、それに加えてブラウザーの解釈も示されます。リクエストをブロックしたか、キャッシュをどう扱ったか、Cookieを送信したか、といった情報です。
リクエストヘッダーとレスポンスヘッダーの全体を見るには、Networkタブ内の任意のリクエストをクリックし、Headersセクションを確認します。「Raw」ビューでは、整形なしで送信されたとおりのヘッダーが表示されます。
リダイレクトチェーンを見るには、3xxステータスコードのリクエストを探します。ブラウザーはそれらを最終リクエストの下にまとめますが、展開すると各ステップを確認できます。ここで、リダイレクトループ、欠落した Location ヘッダー、誤ったドメインを指すリダイレクトが見つかります。
タイミングを見るには、任意のリクエストのTimingタブを確認します。DNSルックアップ、TCP接続、TLSハンドシェイク、サーバー待機にブラウザーが費やした時間が表示されます。リダイレクトが遅い場合、Timingタブを見ると、問題がネットワーク遅延なのかサーバー処理なのかが分かります。
制限もあります。ブラウザーはセキュリティ上の理由で一部のヘッダーを隠します。Set-Cookie ヘッダーは表示されますが、実際のCookie値は伏せられます。Authorization ヘッダーは完全に隠されることもあります。それらを見る必要がある場合は、curl を使ってください。
mitmproxy: インターセプトプロキシ
mitmproxy はPython製のツールで、ブラウザーとサーバーの間に入り、すべてのリクエストとレスポンスをリアルタイムで表示します。curl より複雑ですが、ブラウザーが自動的に追加するヘッダーを含め、ブラウザーが実際に送信している内容を見せてくれる唯一のツールです。
起動するには:
mitmproxy
次に、ブラウザーで localhost:8080 をHTTPプロキシとして使用するように設定します。mitmproxy はすべてのリクエストをターミナルインターフェースに表示します。ヘッダーの調査、送信前のリクエスト編集、異なるパラメーターでのリクエスト再実行ができます。
これは、ブラウザーでしか起きない問題のデバッグに役立ちます。CORSプリフライトリクエスト、Cookieの扱い、特定のヘッダーが存在すると失敗するリクエストなどです。また、企業プロキシやVPNの背後でサイトがどう振る舞うかをテストする場合にも有用です。mitmproxy はそうした環境をシミュレートできるからです。
欠点はセットアップの複雑さです。mitmproxy がHTTPSトラフィックをインターセプトできるようにルート証明書をインストールする必要があり、ブラウザーでプロキシを使用する設定も必要です。素早い確認には curl のほうが速いです。深いデバッグには、mitmproxy はセットアップに時間をかける価値があります。
webpagetest: 本番視点
WebPageTestは、実際のブラウザーでさまざまな場所からページを読み込み、HTTPのやり取り全体を表示する無料サービスです。curl より遅いものの、CDNの挙動、DNS解決、TLSネゴシエーションを含め、実際のユーザーが経験する内容を見せてくれます。
「Request Headers」と「Response Headers」ビューでは、ブラウザーが送信および受信した内容を正確に確認できます。「Waterfall」ビューでは、リダイレクトを含むすべてのリクエストのタイミングが表示されます。ここで、特定の地域や特定のネットワークでしか発生しない問題が見つかります。
WebPageTestは、メインドキュメントのリダイレクトチェーンも表示します。リダイレクト問題の多くはここにあります。サイトが http:// から https:// へ、次に www. から非 www. へ、さらに / から /en/ へリダイレクトする場合、WebPageTestは3つのステップすべてと、それぞれにかかった時間を表示します。
こうしたHTTPの基礎を検証および最適化するためのツールとして、Wux Webtools offers several utilities があり、ヘッダーアナライザーやリダイレクトチェッカーを含む複数のユーティリティをブラウザー内だけで実行できます。すべてをクライアント側で処理するため、プライバシーにも配慮されています。
ヘッダーが嘘をつくとき
最も難しいHTTPの問題は、サーバーが矛盾するヘッダーを送る場合です。Cache-Control ヘッダーは no-cache と言っているのに、Expires ヘッダーはリソースが1年間有効だと言っている。Location ヘッダーは相対URLを指しているのに、Content-Location ヘッダーは別の場所を指している。ブラウザーはどちらを信頼するか推測しなければならず、ブラウザーによって推測が異なります。
このような場合は、サーバーが送った順序で生のヘッダーを見る必要があります。curl -v はそれを行えます。mitmproxy も同様です。ブラウザーのDevToolsは読みやすさのためにヘッダーを並べ替えることがあり、それによって問題が見えなくなります。
もう1つのよくある問題は、アプリケーションではなくCDNやロードバランサーによって追加されるヘッダーです。キャッシュ問題をデバッグしている場合、Cache-Control ヘッダーがアプリから来たのかCDNから来たのかを知る必要があります。curl は最終結果を見せてくれますが、各ヘッダーがどこから来たかは教えてくれません。そのためには、CDNをバイパスして(オリジンサーバーを直接叩いて)ヘッダーを比較する必要があります。
リダイレクトループの問題
リダイレクトループは、本番環境で最も一般的なHTTPの問題です。2つのサーバーが、URLの向き先について意見が一致していないときに発生します。CDNがオリジンへリダイレクトし、オリジンがCDNへリダイレクトし返す。あるいは、ロードバランサーがHTTPをHTTPSへリダイレクトする一方で、アプリが X-Forwarded-Proto ヘッダーを見ていないためにHTTPSをHTTPへ戻してしまう、というケースです。
これをデバッグするには、各ステップの Location ヘッダーを含む完全なリダイレクトチェーンを見る必要があります。curl -L -v はこれを行えますが、無限ループを防ぐために50回のリダイレクトで停止します。その制限に達しているなら、リダイレクトループがあります。
修正は通常、設定変更です。アプリに X-Forwarded-Proto ヘッダーを信頼させる、またはCDNに、すでにHTTPSであるリクエストをリダイレクトしないよう指示する、といった対応です。しかし、ループが見えるまでは修正できません。ブラウザーは諦める前に数回分のリダイレクトしか表示してくれません。
最初に確認すること
本番環境で何かが壊れたら、次の順序で確認します:
- ステータスコード: 期待どおりですか。301は恒久的、302は一時的、307はHTTPメソッドを維持します。誤ったコードが見えている場合、問題はリダイレクト設定にあります。
- Locationヘッダー: 正しい場所を指していますか。絶対URLですか、それとも相対URLですか。相対URLは現在のURLを基準に解決されるため、ベースURLが想定と違う場合、予期しない結果になります。
- キャッシュヘッダー: ブラウザーがリダイレクトをキャッシュしていませんか。301リダイレクトはデフォルトでキャッシュされるため、設定ミスのあるリダイレクトは、修正後も数時間サイトを壊し続けることがあります。
Cache-ControlとExpiresヘッダーを確認し、ブラウザーがそのリダイレクトをどれくらい記憶するかを見ます。
- CORSヘッダー: リクエストがクロスオリジンの場合、サーバーは正しい
Access-Control-Allow-Originヘッダーを送っていますか。そうでなければ、ブラウザーはリクエストをブロックし、コンソールにCORSエラーが表示されます。これはサーバーのレスポンスヘッダーでしか修正できません。ブラウザー側で回避することはできません。
- タイミング: リクエストにはどれくらい時間がかかりましたか。遅い場合、それはネットワーク遅延ですか、それともサーバー処理ですか。ブラウザーのDevToolsとWebPageTestはいずれも、時間がどこに使われたかを示すタイミングの内訳を表示します。
プライバシーとヘッダーをめぐるブラウザーの挙動がどのように変化してきたかをさらに詳しく知るには、what changed for cookies in 2026 and what to do about it を参照してください。最近のブラウザー更新がヘッダーと同意に与える影響を扱っています。
重要なポイント
curl -L -vは、ブラウザーによる解釈なしに、完全なリダイレクトチェーンとすべてのヘッダーを表示します- ブラウザーのNetworkタブは、キャッシュやCORSの判断を含め、ブラウザーがレスポンスに対して何をしたかを示します
mitmproxyは、ブラウザーが自動的に追加するヘッダーを含め、ブラウザーが何を送信したかを示します- WebPageTestは、CDNの挙動や地域差を含め、実際のユーザーが経験する内容を示します
- リダイレクトループと矛盾するヘッダーは、本番環境で最も一般的な問題であり、生のHTTPを調べなければ見えません
FAQ
Q: curlがブラウザーと異なるヘッダーを表示するのはなぜですか?
A: ブラウザーはヘッダー(User-Agent、Accept、Cookie)を自動的に追加し、キャッシュやCORSについて独自のルールに従うためです。curl は、指示されたものだけを送信します。ブラウザーが実際に送信している内容を見るには、mitmproxy またはブラウザーのDevToolsを使用してください。
Q: 一部のユーザーにだけ発生するリダイレクトをどうデバッグすればよいですか?
A: リダイレクトが、ユーザーが送信するヘッダーに依存していないか確認します。User-Agent、Accept-Language、Cookie、またはIPアドレス(X-Forwarded-For 経由)です。curl を使ってユーザーが送信したものと同じヘッダーを送るか、WebPageTestを使ってユーザーの場所からページを読み込んでください。
Q: 301リダイレクトと302リダイレクトの違いは何ですか?
A: 301は恒久的で、ブラウザーにリダイレクトをキャッシュするよう伝えます(場合によっては永久に)。302は一時的で、ブラウザーにキャッシュしないよう伝えます。どちらを使うべきか分からない場合は、302を使ってください。あとでいつでも301に変更できます。
Q: curlではリダイレクトが動くのに、ブラウザーでは動かないのはなぜですか?
A: おそらく、ブラウザーが古いリダイレクトをキャッシュしているか、CORSまたは混在コンテンツのルールによってブラウザーがリダイレクトをブロックしているためです。ブラウザーのDevToolsコンソールでエラーを確認し、Cache-Control ヘッダーを見て、ブラウザーがキャッシュされたレスポンスを使用していないか確認してください。
Q: CDNが追加するヘッダーを見るにはどうすればよいですか?
A: curl でCDNのURLにアクセスし、次にもう一度 curl を使ってCDNをバイパスし、オリジンサーバーを直接叩きます。ヘッダーを比較してください。最初のレスポンスにだけ現れるヘッダーは、CDNから来たものです。
<!-- tool-cta:start -->
💡 お試しください: リダイレクトの問題を追跡する際、Redirect Checker はチェーン全体をたどり、各ホップでステータスコードとヘッダーを表示します。
<!-- tool-cta:end -->
Sources
- curl documentation — curlのコマンドラインオプションと挙動に関する公式リファレンス
- HTTPie documentation — httpieの構文と機能のガイド
- MDN Web Docs: HTTP redirections — HTTPリダイレクトのステータスコードと挙動に関する包括的な説明
- WebPageTest documentation — WebPageTestの結果とヘッダーの読み解き方


