【実務・中級編】HTTP/1.1のコンテンツネゴシエーション(Accept, Accept-Language) – HTTPプロトコル・通信規格実践ガイド

なぜHTTP/1.1の「ネゴシエーション」で、現場のエンジニアは沼にハマるのか

ネットワークの世界で長く飯を食っていると、避けて通れないのが「意図しないコンテンツ」が返ってくるという不可解なトラブルだ。ブラウザの言語設定は日本語なのに、なぜか英語のレスポンスが返ってくる。APIを叩くと、期待したJSONではなくHTMLが降ってくる。

これらはすべて、HTTP/1.1が持つ「コンテンツネゴシエーション(Content Negotiation)」という、古くからあるけれど意外と奥が深い仕組みが引き起こす現象だ。RFC 7231に明記されているこの仕様を正しく理解していないと、CDNのキャッシュ戦略で大火傷を負うことになる。今日は、その泥臭い実態と、現場で確実に制御するための作法を解説しよう。

—

1. サーバーとクライアントの「すれ違い」を埋めるヘッダーたち

HTTP/1.1のネゴシエーションは、クライアントが「私はこれが欲しい」と提示し、サーバーが「じゃあ、これなら出せる」と選定する、いわば「お見合い」のようなものだ。

ここで主役となるのが、以下のリクエストヘッダーだ。

  • `Accept`: クライアントが処理可能なメディアタイプ(MIMEタイプ)。
  • `Accept-Language`: クライアントが好む自然言語。
  • `Accept-Encoding`: 圧縮アルゴリズム(gzip, brなど)。

現場で見るべき「q値(Quality Values)」のルール

ただヘッダーを並べるだけではない。エンジニアとして押さえておくべきは「q値」だ。`q=0.0`から`q=1.0`までの重み付けが、優先順位を決定する。

クライアントのリクエスト例
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,/;q=0.8
Accept-Language: ja,en-US;q=0.7,en;q=0.3

  • `q`値がない場合は、デフォルトで`1.0`とみなされる。
  • `q=0`は「受け取れない」を意味する。
  • サーバーはこの重み付けを見て、最も「スコアが高い」リソースを返却する義務がある。

—

2. 実践:curlでネゴシエーションをハックする

デバッグの基本は、ブラウザという「ブラックボックス」を通さず、生のHTTPリクエストを投げることだ。以下のコマンドを叩いて、サーバーがどう反応するかを見てみてほしい。

Accept-Languageを強制的に英語にして、サーバーの反応を確認する
curl -v -H “Accept-Language: en-US,en;q=0.5” https://example.com/api/resource

もしここで「期待した日本語が返ってこない」のであれば、サーバー側のロジックか、あるいは「Varyヘッダー」の設定に不備がある可能性が高い。

—

3. インフラエンジニアの落とし穴:Varyヘッダーを軽視するな

ここからが本題だ。Web APIを設計する際、キャッシュサーバー(CDNやNginx)と連携する場合、`Vary`ヘッダーを適切に設定しないと、地獄を見る。

`Vary`ヘッダーは、「どのリクエストヘッダーを見てレスポンスを出し分けているか」をキャッシュサーバーに教えるための通行手形だ。

Nginxでの設定例

もしあなたがNginxをリバースプロキシとして運用しているなら、以下の設定を忘れてはいけない。

location /api/ {
# 応答がAccept-Languageヘッダーに依存していることをCDNに伝える
add_header Vary “Accept-Language”;

# これを忘れると、最初にアクセスした人の言語設定がキャッシュされ、
# 次のユーザーに同じ言語が強制される「キャッシュ汚染」が起きる
}

—

4. クライアント側の実装:Fetch APIでの制御

フロントエンドエンジニアがAPIを叩く際、デフォルトのブラウザ挙動に任せきりにしていないだろうか?特定の言語のデータが必要な場合は、明示的にヘッダーを付与するのがプロの流儀だ。

// 特定言語のリソースを確実に取得する実装
fetch(‘https://api.example.com/v1/profile’, {
headers: {
‘Accept’: ‘application/json’,
‘Accept-Language’: ‘ja-JP’ // ブラウザの言語設定を無視して明示的に指定
}
})
.then(response => {
if (response.status === 406) {
console.error(‘サーバーが要求したメディアタイプに対応していません’);
}
return response.json();
});

—

まとめ:ネットワークスペシャリストからの提言

HTTP/1.1のネゴシエーションは古臭い技術に見えるかもしれないが、マルチリンガルなサービスや、APIのバージョン管理において、今なお強力なツールだ。

1. 優先順位の理解: `q`値がすべて。サーバー側の実装で「どれが一番重いか」をちゃんと計算できているか確認すること。
2. キャッシュの意識: `Vary`ヘッダーを設定しないCDN運用は、時限爆弾を埋めるのと同じだ。
3. デバッグの徹底: 悩んだらまず`curl -v`。ヘッダーの送受信を可視化すれば、大抵のバグは解消できる。

ネットワークは「魔法」ではない。パケットがどう流れ、サーバーがどう判断しているか。その裏側にあるプロトコルの美学を理解すれば、どんなトラブルも怖くはないはずだ。さあ、次は君の環境の`Vary`ヘッダーを確認するところから始めてみてくれ。

コメント

タイトルとURLをコピーしました