HTTPQUERY
日本語

Content-Type

使い方

Content-Type ヘッダーは、含まれているコンテンツのメディアタイプをクライアント(リクエストボディの場合はサーバー)に伝えます。メディアタイプは、受信側がボディをどう解析し描画するかを決めます。このヘッダーがないと、クライアントは MIME スニッフィングに頼ることになり、セキュリティ上のリスクと一貫性のない挙動を招きます。

注意

Accept はクライアントが何を受け取りたいかを宣言します。Content-Type は何が送られているかを宣言します。Accept はリクエストに現れます。Content-Type はリクエスト(ボディがある場合)とレスポンスの両方に現れます。GET リクエストには通常ボディがなく、Content-Type も不要です。ボディを伴う POST や PUT のリクエストにはこのヘッダーが必要です。

メディアタイプは、スラッシュで区切られたトップレベルタイプとサブタイプからなり、任意でパラメーターが続きます。Accept リクエストヘッダーは、コンテンツネゴシエーションにおいて Content-Type と連携し、サーバーが選択する前にクライアントが希望するメディアタイプを表明できるようにします。

サーバーや中間装置は、送信前に Content-Encoding(gzip や br など)を適用することがあります。Content-Type ヘッダーは常に、エンコード後の形式ではなく、エンコード前の元のメディアタイプを記述します。

MIME-Version ヘッダーは MIME タイプのメールにおける起源に由来し、一部の HTTP メッセージに現れますが、HTTP はメディアタイプの処理にこのヘッダーを必要としません。

media-type

メディアタイプの値は、IANA に登録された type/subtype の形式に従います。一般的なタイプには text/html、application/json、image/png、application/octet-stream があります。完全なレジストリは IANA が管理しています。

charset

charset パラメーターは、テキストベースのメディアタイプにおける文字エンコーディングを指定します。UTF-8 が Web で支配的なエンコーディングです。

Content-Type: text/html; charset=UTF-8

boundary

boundary パラメーターは multipart/* のメディアタイプで必須です。boundary の文字列がマルチパートボディの各パートを区切ります。boundary の値は、いずれのボディパートの中にも現れてはいけません。

Content-Type: multipart/form-data; boundary=----FormBoundary

例

サーバーが UTF-8 エンコーディングの HTML ページを返します。ブラウザはメディアタイプを使ってコンテンツを Web ページとして描画し、charset を使ってテキストを正しくデコードします。

Content-Type: text/html; charset=UTF-8

API が JSON のレスポンスを返します。application/json のメディアタイプは、ボディを JSON として解析するようクライアントに指示します。

Content-Type: application/json

API のエラーレスポンスが application/problem+json のメディアタイプを使い、構造化された problem details のペイロードであることを示します。

Content-Type: application/problem+json

クライアントが Accept: text/markdown を送ると、CDN が HTML ページをその場で Markdown に変換します。レスポンスは Content-Type として text/markdown を運び、ボディが HTML ではなく Markdown であることを示します。

Content-Type: text/markdown; charset=utf-8

AI エージェントと Content-Type

Cloudflare のような CDN プロバイダーは、Content-Type: text/markdown とともに、変換後の文書のトークン数を見積もる x-markdown-tokens ヘッダーを返します。エージェントはコンテンツタイプを使って正しいパーサーを選び、トークンの見積もりを使ってコンテキストウィンドウの予算を管理します。

ファイルのアップロードでは multipart/form-data を使い、boundary の文字列がリクエストボディ内のフォームフィールドとファイルデータを区切ります。

Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW

サーバーがバイナリファイルのダウンロードを配信します。application/octet-stream のタイプは生のバイナリデータを示し、attachment に設定した Content-Disposition ヘッダーと組み合わせることがよくあります。

Content-Type: application/octet-stream

multipart/byteranges のレスポンスは、1 つのリソースから複数のバイト範囲を配信します。各パートは独自の Content-Type ヘッダーと Content-Range ヘッダーを持ちます。

Content-Type: multipart/byteranges; boundary=THIS_STRING_SEPARATES

トラブルシューティング

描画の失敗や解析エラーは、Content-Type ヘッダーの欠落や誤りにさかのぼれることがよくあります。

charset パラメーターがないために文字化けする。charset が宣言されていない場合、ブラウザは既定のエンコーディング(多くは ISO-8859-1)にフォールバックします。非 ASCII の文字は文字化けして表示されます。charset パラメーターを明示的に加えてください。Content-Type: text/html; charset=UTF-8 のようにします。nginx では次のようにします。

charset utf-8;

Apache では次のようにします。

AddDefaultCharset UTF-8

正しい Content-Type があるのにブラウザが MIME スニッフィングを行う。ブラウザは宣言された型を無視し、ボディの内容をスニッフィングして型を判定することがあります。この挙動は、ユーザーがアップロードしたコンテンツが HTML として配信される場合に XSS の攻撃経路を生みます。MIME スニッフィングをブロックするには、X-Content-Type-Options ヘッダーを nosniff に設定してください。

X-Content-Type-Options: nosniff

API が application/json ではなく text/html を返す。API から JSON を解析するクライアントが、HTML のエラーページやフレームワークの既定のレスポンスを受け取ります。これは、エラーハンドラーやリバースプロキシがレスポンスを横取りし、Content-Type を更新しないままボディを差し替えた場合に起こります。オリジンサーバー、アプリケーションフレームワーク、リバースプロキシ、CDN というレスポンスの連鎖全体を確認してください。Express.js では res.json() を呼ぶと正しいヘッダーが自動的に設定されます。Django では HttpResponse ではなく JsonResponse を返します。

マルチパートの boundary の不一致でファイルのアップロードが壊れる。Content-Type ヘッダーで宣言した boundary の文字列は、リクエストボディで使われる区切り文字と一致していなければなりません。不一致があると、サーバーはマルチパートのボディの解析に失敗します。DevTools の Network タブの Headers と Payload のセクションで生のリクエストを調べてください。FormData オブジェクトとともに fetch() や XMLHttpRequest を使う場合は、boundary を手動で設定しないでください。リクエストから Content-Type ヘッダーを省略すれば、ブラウザが正しい boundary を自動的に生成します。

フレームワークの既定の Content-Type が明示的な設定を上書きする。一部のフレームワークは、アプリケーションのコードが実行された後に Content-Type を設定します。Express.js、Django、Spring Boot のミドルウェアがヘッダーをリセットすることがあります。ミドルウェアの実行順序を確認してください。Express.js では、ヘッダーを変更するすべてのミドルウェアの後に res.type() や res.set(‘Content-Type’, …) が呼ばれるようにします。

DevTools で Content-Type の問題を診断する。ブラウザの DevTools の Network タブを開き、リクエストを選択して Response Headers のセクションで Content-Type の値を調べてください。宣言された型を、Response や Preview のタブに表示される実際のボディの内容と比較します。ブラウザの影響を受けずにコマンドラインからヘッダーを確認するには curl -I https://example.re/api/data を使います。