Geonode logo
Geonode Team

Geonode Team

更新日:2026年10月7日

公開日:2026年9月2日

curl を使ってレスポンスヘッダーを表示する方法

curl はデフォルトでレスポンスヘッダーを非表示にします。4つのオプションでこれらを表示できますが、その違いは、ドキュメントに記載されている以上に重要な点があります。 そのうちの1つは、デバッグしようとしているリクエストとは異なるリクエストを送信してしまうため、実際には存在しない不一致を追いかけて1時間も無駄にしてしまうことになりかねません。 このガイドでは、これら4つのオプションすべてに加え、多くの人が知らないJSON出力や、プロキシを経由した場合の状況の変化についても解説します。

私たちがこれを重視する理由:私たちはGeonodeであり、プロキシを販売しています。そして、レスポンスヘッダーこそが、お客様から最も多く寄せられる質問――「これはプロキシの問題なのか、そうでないのか?」――に答える最も手っ取り早い方法だからです。ブロックページ、レート制限、そして真正なエラーは、ブラウザ上では同じように見えますが、ヘッダーでは全く異なるものになります。 429 に Retry-After が含まれている場合は、アクセス速度が速すぎることを意味し、プロキシでは解決できません。403 に security-vendor ヘッダーが含まれている場合は、ターゲット側があなたを特定したことを意味します。 407というレスポンスは、プロキシが認証情報を要求していることを意味します。何かを変更する前にヘッダーを確認しておけば、推測の手間を大幅に省くことができます。また、curlにはこの特定のケースに対応するフラグ——%{proxy_used}(バージョン8.7.0で追加)——があり、転送がプロキシを経由した場合は1を返します。設定が反映されたかどうか確信が持てない場合に役立ちます。

4つのオプションの概要

オプション表示送信適した用途
-iレスポンスヘッダー + ボディ実際のリクエスト日常的な確認
-IレスポンスヘッダーのみHEADリクエスト簡単な確認(注意点あり)
-D fileレスポンスヘッダーをファイルに出力実際のリクエストスクリプト作成、ストリームの分離
-vリクエストおよびレスポンスヘッダー実際のリクエスト送信内容のデバッグ

重要なのは2番目の行であり、この分野における混乱の大部分の原因となっています。それ以外は、出力がどこに送られるかという問題に過ぎません。

-i

: ヘッダーと本文 日常的に使われるオプションです。curlマニュアルでは、-i, --show-headers として次のように説明されています。「出力にレスポンスヘッダーを表示します…このオプションを指定すると、レスポンスヘッダーがデータと同じストリーム/出力に保存されます。」

curl -i https://example.com
HTTP/2 200
content-type: text/html; charset=UTF-8
content-length: 1256
cache-control: max-age=604800
date: Wed, 02 Sep 2026 10:14:22 GMT

<!doctype html>...

ヘッダー、空行、そして本文 — ワイヤ形式と同じ構造です。

古い資料を読んでいる人がつまずきがちな命名に関する注意点:長い形式は現在 --show-headers となっています。以前は --include でしたが、どちらも機能します。ただし、現在のドキュメントでは新しい名称が使用されています。

知っておくべき2つの詳細があります。出力がターミナルに送られる場合、curlはヘッダー名を太字で表示したり、Location: 形式のURLにマークを付けたりすることがありますが、これは対話モードでは便利ですが、パイプラインでは望ましくありません。--no-styled-output でこれを無効にできます。また、ヘッダーと本文は同じストリームを共有するため、-i と-o file を指定すると、両方がファイルに書き込まれてしまいますが、これはほとんどの場合望ましくありません。その場合は、-D を使用してください。

-I:ヘッダーのみの取得、そしてそれが誤解を招く理由 `

`-I`` については、次のように説明されています。「ヘッダーのみを取得します。HTTPサーバーには『HEAD』コマンドがあり、このメソッドはそれを利用して、ドキュメントのヘッダーのみを取得します。」

この説明をよく読んでください。これは、レスポンスを取得して本文を破棄するわけではありません。 別のHTTPメソッドを送信するのです。

curl -I https://example.com

これはHEADリクエストであり、その影響は現実のものとなります:

一部のサーバーはHEADを異なる方法で処理します。 HEAD では、異なるヘッダーやステータスコードが返されたり、405 Method Not Allowedで完全に拒否されたりすることがありますが、同等の GET は問題なく動作します。

一部のフレームワークは HEAD リクエストのボディを計算しないため、Content-Length、ETag、Content-Type が欠落していたり、誤っていたりする可能性があります。

CDN やキャッシュは、HEAD を独自のキャッシュキーとして扱うことがよくあります。そのため、キャッシュヘッダーは実際のリクエストで返されるものとは異なる場合があります。

ボット対策システムは異なる応答を返す可能性があります。 通常とは異なるクライアントからの HEAD リクエスト自体がシグナルとなり、返されるチャレンジは GET リクエストで生成されるものとは異なる可能性があります。

したがって、-I は、この URL が有効か、どこにリダイレクトされるか、ファイルのサイズはどれくらいかといった簡単な確認には最適ですが、GET の挙動が異常な理由をデバッグするには信頼性が低くなります。 実際のリクエストを診断する際は、次のメソッドを使用してください:

curl -sS -o /dev/null -D - https://example.com

これは通常の GET を実行し、本体を /dev/null に転送して破棄し、ヘッダーを標準出力にダンプします。これにより、リクエストを変更することなく、-I が提供するのと同様の情報を得ることができます。

特に POST リクエストのヘッダーが必要な場合も、同様のパターンが適用されます:

curl -sS -o /dev/null -D - -X POST -H "Content-Type: application/json" \
     -d '{"a":1}' https://api.example.com/items

-D および -v:ストリームの分離とリクエストの確認

** -D は、ヘッダーを別の出力先に書き出します。** マニュアルには次のように記載されています。「受信したプロトコルヘッダーを指定されたファイルに書き出します……ファイル名として '-'(マイナス記号1つ)を指定すると、標準出力(stdout)に書き出されます。」 また、ヘッダーが受信されなかった場合、このオプションは「空のファイルを作成する」と記載されており、これ自体が診断情報となります。

curl -D headers.txt -o body.html https://example.com

スクリプトで求められるのは、このような明確な分離です。-D -はヘッダーを標準出力(stdout)に送信し、本文は-oが指す先へ送信されます。この組み合わせが、上記のパターンの基礎となっています。

-v もリクエストを表示します。実際、必要なのはこの部分だけという場合がよくあります。マニュアルでは、接頭辞について次のように明確に説明しています:

詳細出力の行には、以下の文字が接頭辞として付きます:> curl から送信されたヘッダー、< curl が受信したヘッダー、} curl から送信されたデータ、{ curl が受信したデータ、* curl が提供する追加情報。

curl -v https://example.com 2>&1 | grep '^>'

これにより、curlが実際に送信した内容が正確にわかります。ただし、ライブラリやデフォルト設定、.curlrcファイルによってヘッダーが追加・上書きされるため、設定した内容とは異なることがよくあります。「サーバーがヘッダーを無視している」という問題の多くは、ここで解決されます。

詳細出力はstderrに出力されるため、パイプ処理の前に2>&1が必要となります。 これは意図的な仕様であり、stdout上のボディをクリーンに保つためです。

マニュアルには、curl 8.10以降、-vを繰り返し指定することでトレースレベルが上がることも記載されています。真に低レベルな作業を行う場合、--trace-asciiを指定すると、「説明情報を含む、すべての送受信データの完全なトレースダンプ」が得られます。この際、可読性を保つために16進数は省略されます。

マニュアルに記載されている、繰り返し強調すべき警告が一つあります。trace および verbose 出力には、「ユーザー名、認証情報、機密データなどの機密情報が含まれている可能性があります。トレースログを他者と共有する際は、この点に留意し、注意してください。」URL を通じて渡されたプロキシの認証情報は、verbose 出力に表示されます。イシュートラッカーに貼り付ける前に、該当部分を伏せてください。

``%{header_json}`

` による機械可読なヘッダーcurl 7.83.0 で追加された、ほとんどの人が見たことのないオプションであり、ヘッダーテキストに対して正規表現を書こうとしていた時には常にこれが正解となります。

マニュアルでは、これを「直近の転送におけるすべての HTTP レスポンスヘッダーを含む JSON オブジェクト。 値は配列として提供されます。これは、複数のヘッダーが存在する場合、複数の値が存在し得るためです。」ヘッダー名は「小文字で、ネットワーク上で出現した順にリスト化」され、重複するヘッダーは「そのヘッダーの最初の出現箇所でグループ化され、各値は JSON 配列として提示」されます。

curl -s -o /dev/null -w '%{header_json}' https://example.com | jq
{
  "content-type": ["text/html; charset=UTF-8"],
  "cache-control": ["max-age=604800"],
  "set-cookie": ["a=1; Path=/", "b=2; Path=/"]
}

これにより、3つの問題が一度に解決されます。名前は小文字に正規化されるため、大文字小文字を区別しないマッチングが行われます。Set-Cookie のような重複するヘッダーは、黙って統合されることなく、配列として渡されます。また、パーサーを記述しなくても出力を解析できます。

単一のヘッダーを抽出するのは非常に簡単になります:

curl -s -o /dev/null -w '%{header_json}' "$URL" | jq -r '.["retry-after"][0] // "none"'

これと相性の良い他の -w 変数:

curl -s -o /dev/null -w 'status=%{response_code} redirects=%{num_redirects} proxy=%{proxy_used} ip=%{remote_ip}\n' "$URL"

response_code は最後の転送の状態、num_redirects は追跡されたリダイレクトの回数、redirect_url は -L を使用しなかった場合にリダイレクトが 本来 向かった先を示し、remote_ip は実際に接続されたアドレス、proxy_used はプロキシが関与していた場合に 1 を返します。最後のものは、NO_PROXY のパターンによってホストが黙って除外されていた可能性がある場合に、実に役立ちます。

リダイレクトチェーンの追跡

-L

を指定しない場合、curl は最初のリダイレクトで処理を停止し、そのレスポンスのみが表示されます。 -L

を指定すると、curl はリダイレクトチェーン内の すべての レスポンスのヘッダーを表示します:

curl -sSL -o /dev/null -D - https://example.com
HTTP/2 301
location: https://www.example.com/

HTTP/2 200
content-type: text/html

各ブロックが 1 ホップです。これにより、URL が 3 回リダイレクトされること、あるホップで HTTP プロトコルに切り替わること、あるいはリダイレクトによって Cookie が失われることを確認できます。

覚えておくと便利な 2 つのパターン:

curl -sSL -o /dev/null -w '%{num_redirects} hops -> %{url_effective}\n' "$URL"

カウントと最終的な宛先が 1 行にまとめられています。 また、リダイレクト先を追跡せずに確認したい場合は:

curl -s -o /dev/null -w '%{redirect_url}\n' "$URL"

リダイレクトチェーンは、多くの人が思っている以上に頻繁に確認する価値があります。各ホップは往復通信に相当し、4つのホップからなるチェーンは実質的な遅延をもたらします。また、予期せぬホップが別のホストを経由していることが、クッキーやCORSの問題の原因であるケースは頻繁にあります。

プロキシを経由したヘッダー

ここで2つの追加事項があります。どちらも、初めて目にする際には混乱を招きがちです。

** 詳細出力には「CONNECT 」というレスポンスが表示されます。** HTTPプロキシを経由したHTTPSの場合、curlはまずトンネルを確立するために「CONNECT 」を発行し、その通信には独自のヘッダーが含まれます:

curl -v -x http://proxy.example.com:8080 https://example.com

CONNECT 、プロキシからのHTTP/1.1 200 Connection established が表示され、その後に初めて実際のリクエストが表示されます。この最初のブロックは、ターゲットではなくプロキシからの通信です。これらを混同してしまうのは、初心者がよく犯すミスです。ターゲットのレスポンスのみを重視する場合は、--suppress-connect-headers を使用することで、出力からこれらのヘッダーを除外できます。

%{http_connect} は、ターゲットのステータスとは別に、CONNECT に対するプロキシのレスポンスコードを報告します。何かが失敗し、どのホップで拒否されたか分からない場合、この区別こそがまさに必要な情報となります:

curl -s -o /dev/null -x "$PROXY" \
  -w 'connect=%{http_connect} status=%{response_code} proxy=%{proxy_used}\n' \
  https://example.com

connect=200 status=403 は、プロキシは正常に動作したが、ターゲットが接続を拒否したことを意味します。connect=407 は、プロキシが認証情報を要求したが、ターゲットに到達しなかったことを意味します。 これら2つの状況では対処法が全く異なり、この区別がなければ、アプリケーションの観点からは同じように見えてしまいます。

また、トンネル経由のHTTPSの場合、プロキシはヘッダーを追加したり読み取ったりすることはできず、暗号化されたバイトを中継しているだけである点にも注意してください。HTTPSレスポンスに予期しないヘッダーが見られる場合、それらはプロキシからではなく、ターゲットまたはその手前にあるCDNから来たものです。

ヘッダーが実際に伝えること

ここまでの要点は、ヘッダーを正しく読み解くことで、単なる推測から正確な診断へとつながるということです。

まずはステータス行から。 200 は成功しました。301/302 はリダイレクトされました。403 は拒否されました。429 はレート制限にかかりました。407 はプロキシ認証が必要です。502/503 はアップストリームのトラブルです。

Retry-After は、429 や 503 と共に表示され、正確にどのくらいの時間待つべきかを示します。この指示に従うことが正しい対応であり、正常な状態に戻るための最速の道でもあります。これを無視してすぐに再試行すると、一時的な制限が長期化してしまう原因となります。

Content-Type には、実際に受け取った内容が示されています。APIエンドポイントで「text/html」と表示される場合、JSONではなくエラーページが返されたことを意味し、これは解析失敗の大部分の原因となります。

Content-Length と実際に届いた内容との比較。 宣言された長さが長いのに本文が短い場合は、切り捨てが発生しています。

キャッシュヘッダー — Cache-Control、ETag、Last-Modified — は、再取得を回避できるかどうかを示します。後続のリクエストで If-None-Match や If-Modified-Since が含まれている場合、完全な転送が 304 に変換され、帯域幅が課金制の場合には直接的な節約につながります。

Set-Cookie は、サーバーがどのようなセッション状態を確立しようとしているかを示しており、期待していた場所にこれが存在しないことは、多くの認証に関する謎を説明してくれます。

Server およびベンダー固有のヘッダー は、オリジンの前に何があるかを特定します。セキュリティベンダーのヘッダーを含み、403 を持つレスポンスは、ブロックがアプリケーションではなく保護レイヤーから発生したことを示しています。これは、異なる問題であり、異なる対応が必要です。

非標準ヘッダー。 レート制限の予算、リクエスト識別子、API固有のメタデータは、x-というプレフィックスが付いたヘッダーとして表示されることが多く、これらはレスポンスの中で最も有用な情報であることが多い。リクエストIDは、サポート担当者が尋ねてくる情報である。

よくある質問

curl でレスポンスヘッダーを確認するにはどうすればよいですか?

curl -i URL を実行すると、ヘッダーの後にボディが表示されます。 curl -D - URL を実行すると、ヘッダーが標準出力に個別に書き出されます。 curl -v URL を実行すると、リクエストヘッダーとレスポンスヘッダーの両方が表示されます。実際のリクエストをデバッグする際は、-I の使用を避けてください。これは GET ではなく HEAD リクエストを送信してしまうためです。

curl の -i と -I の違いは何ですか?

-i は、実際のリクエストの本文とともにレスポンスヘッダーを含みます。-I は代わりに HEAD リクエストを送信するため、結果が異なる可能性のある別のリクエストとなります。実際にデバッグしているリクエストのヘッダーが必要な場合は、-i または -o /dev/null -D - を使用してください。

本文なしでヘッダーのみを表示するにはどうすればよいですか?

curl -sS -o /dev/null -D - URL。これは通常の GET リクエストを実行し、本文を破棄してヘッダーを出力します。これにより、HTTP メソッドを変更することなく、-I と同じ結果を得ることができます。一部のサーバーは HEAD リクエストに対して異なる応答を返したり、完全に拒否したりするため、これは重要な点です。

curl が送信するリクエストヘッダーを確認するには?

curl -v URL を実行し、> で始まる行を探してください。これらが curl が送信したヘッダーです。詳細出力は stderr に出力されるため、フィルタリングしたい場合は 2>&1 にパイプしてください。これにより、設定したヘッダーが実際に通信されていることを確認できます。

curlのヘッダーをJSON形式で取得するにはどうすればよいですか?

curl -s -o /dev/null -w '%{header_json}' URL。curl 7.83.0で追加されたこのオプションは、すべてのレスポンスヘッダーを、小文字の名称と配列値を持つJSONオブジェクトとして出力します。これにより、Set-Cookieのような重複するヘッダーも、結合されることなく保持されます。フィールドを抽出するには、jq にパイプしてください。

プロキシを使用すると、なぜヘッダーが2セット表示されるのですか?

HTTPプロキシを経由したHTTPSの場合、curlはまずトンネルを開くために CONNECT を送信し、それに対するプロキシの応答がターゲットの応答よりも先に表示されます。これを非表示にするには --suppress-connect-headers を使用するか、ターゲットとは別にプロキシのステータスコードを確認するには %{http_connect} を使用してください。

各リダイレクトのヘッダーを確認するにはどうすればよいですか?

-L を追加して curl にリダイレクトを追跡させ、-D - または -i を使用します。curl はチェーン内のすべてのレスポンスのヘッダーを、ホップごとに1ブロックずつ出力します。%{num_redirects} および %{url_effective} を使用すると、カウントと最終的な URL が1行で表示されます。

レスポンスヘッダーから、自分がブロックされているかどうかがわかりますか?

多くの場合、その通りです。しかも、レスポンス本文よりも確実に判断できます。429 に Retry-After が含まれている場合は、レート制限です。403 にセキュリティベンダーのヘッダーが含まれている場合は、保護レイヤーです。APIエンドポイントで 200 に Content-Type: text/html が含まれている場合は、認証要求またはログインページです。それぞれに対処法が異なり、それらを区別できるのはヘッダーだけです。

まとめ

4つの選択肢と、1つのよくある落とし穴。日常的な確認には -i、ヘッダーを本文から分離したい場合は -D -、送信内容と受信内容の両方を確認したい場合は -v、そしてサーバーが稼働しているかを手っ取り早く確認したい場合のみ -I を使用してください。 は HEAD リクエストを送信するため、サーバーは GET リクエストとは異なる応答を返す可能性があるからです。

この記事から一つだけ取り入れるとすれば、%{header_json} をお勧めします。現在、正規表現でヘッダーテキストを解析しているスクリプトは、すべてこれに置き換えるべきです。小文字のヘッダー名、繰り返しヘッダー用の配列、そして jq が読み取れる形式での出力が得られます。%{response_code}、%{num_redirects}、%{proxy_used} と組み合わせることで、ヘッダーの確認作業を、目視確認ではなく、アサーションで検証できるものに変えることができます。

また、リクエストに問題が発生した場合は、何かを変更する前にヘッダーを確認してください。ステータスコード、Retry-After、Content-Type、およびそれらの間に含まれるベンダーヘッダーは、通常、問題の原因を明確に示しています。これは、何かが機能するまで設定を試し続けるよりもはるかに効率的であり、所要時間は約10秒です。