コンテンツネゴシエーション

コンテンツネゴシエーションとは?

コンテンツネゴシエーションは、クライアントが処理できるものとサーバーが処理できるものに基づいて、クライアントに返すコンテンツの種類を決定する方法です。これを使用して、クライアントがHTMLまたはJSONのどちらを要求しているか、画像をJPEGまたはPNGとして返すか、どのような圧縮がサポートされているかなどを判断できます。これは、それぞれ複数の値オプションをサポートし、それぞれ独自の優先順位を持つ4つの異なるヘッダーを分析することによって行われます。

これを手動で一致させるのは非常に困難です。CodeIgniterは、これを処理できるNegotiatorクラスを提供します。

本質的に、コンテンツネゴシエーションは、単一の資源が複数の種類のコンテンツを提供することを可能にするHTTP仕様の一部であり、クライアントが最適なデータの種類を要求することを可能にします。

これの古典的な例として、PNGファイルを表示できないブラウザがGIFまたはJPEG画像のみを要求する事が挙げられます。サーバーがリクエストを受け取ると、クライアントが要求している利用可能なファイルの種類を確認し、サポートしている画像フォーマットから最適な一致を選択し、この場合はJPEG画像を返す可能性が高いです。

この同じネゴシエーションは、4種類のデータで発生する可能性があります。

  • メディア/ドキュメントの種類 - これは画像フォーマット、またはHTML対XMLまたはJSONなどです。

  • 文字セット - 返されるドキュメントに設定する必要がある文字セット。通常はUTF-8です。

  • ドキュメントエンコーディング - 通常は結果に使用される圧縮の種類。

  • ドキュメント言語 - 複数の言語をサポートするサイトの場合、これは返す言語を決定するのに役立ちます。

クラスの読み込み

Serviceクラスを使用して、クラスのインスタンスを手動で読み込むことができます。

<?php

$negotiate = \Config\Services::negotiator();

これにより、現在のリクエストインスタンスが取得され、Negotiatorクラスに自動的に注入されます。

このクラスを単独でロードする必要はありません。代わりに、このリクエストのIncomingRequestインスタンスからアクセスできます。このようにして直接アクセスすることはできませんが、negotiate()メソッドを介してすべてのメソッドに簡単にアクセスできます。

<?php

$request->negotiate('media', ['foo', 'bar']);

このようにアクセスする場合、最初の引数は一致しようとしているコンテンツの種類であり、2番目の引数はサポートされている値の配列です。

ネゴシエーション

このセクションでは、ネゴシエートできる4種類のコンテンツについて説明し、上記で説明した2つのメソッドの両方を使用してそれがどのように見えるかを示します。

メディア

最初に検討する点は、「メディア」ネゴシエーションの処理です。これらはAcceptヘッダーによって提供され、利用可能な最も複雑なヘッダーの1つです。一般的な例として、クライアントがサーバーにデータの形式を伝えることが挙げられます。これは、特にAPIで一般的です。たとえば、クライアントはAPIエンドポイントからJSON形式のデータ要求を行う場合があります。

GET /foo HTTP/1.1
Accept: application/json

サーバーは、提供できるコンテンツの種類のリストを提供する必要があります。この例では、APIは、生のHTML、JSON、またはXMLとしてデータを返すことができます。このリストは優先順位に従って提供する必要があります。

<?php

$supported = [
    'application/json',
    'text/html',
    'application/xml',
];

$format = $request->negotiate('media', $supported);
// or
$format = $negotiate->media($supported);

この場合、クライアントとサーバーは両方ともデータをJSONとしてフォーマットすることに同意できるため、「json」がネゴシエートメソッドから返されます。デフォルトでは、一致が見つからない場合、$supported配列の最初の要素が返されます。ただし、場合によっては、フォーマットを厳密な一致にする必要がある場合があります。trueを最後の値として渡すと、一致が見つからない場合は空の文字列が返されます。

<?php

$format = $request->negotiate('media', $supported, true);
// or
$format = $negotiate->media($supported, true);

言語

もう1つの一般的な用途は、コンテンツを提供する言語を決定することです。単一言語サイトのみを実行している場合、これはあまり違いを生み出しませんが、コンテンツの複数の翻訳を提供できるサイトでは、ブラウザは通常、Accept-Languageヘッダーに優先言語を送信するため、これは役立ちます。

GET /foo HTTP/1.1
Accept-Language: fr; q=1.0, en; q=0.5

この例では、ブラウザはフランス語を優先し、2番目の選択肢として英語を選択します。Webサイトで英語とドイツ語をサポートしている場合は、次のようにします。

<?php

$supported = [
    'en',
    'de',
];

$lang = $request->negotiate('language', $supported);
// or
$lang = $negotiate->language($supported);

この例では、「en」が現在の言語として返されます。一致が見つからない場合、$supported配列の最初の要素が返されるため、常に優先言語にする必要があります。

エンコーディング

Accept-Encodingヘッダーには、クライアントが受信することを希望する文字セットが含まれており、クライアントがサポートする圧縮の種類を指定するために使用されます。

GET /foo HTTP/1.1
Accept-Encoding: compress, gzip

Webサーバーは、使用できる圧縮の種類を定義します。Apacheなどの一部は、gzipのみをサポートしています。

<?php

$type = $request->negotiate('encoding', ['gzip']);
// or
$type = $negotiate->encoding(['gzip']);

詳しくは、Wikipediaをご覧ください。

文字セット

目的の文字セットは、Accept-Charsetヘッダーを介して渡されます。

GET /foo HTTP/1.1
Accept-Charset: utf-16, utf-8

デフォルトでは、一致が見つからない場合、utf-8が返されます。

<?php

$charset = $request->negotiate('charset', ['utf-8']);
// or
$charset = $negotiate->charset(['utf-8']);