HTTP ヘッダーに基づくコンテンツ・ネゴシエーションの実装

REST (Representational State Transfer) アプリケーションは、リソースの異なる表示を戻すことができます。 HTTP Accept ヘッダー に基づくコンテンツ・ネゴシエーションを使用して、サーバーとクライアントの間の データ交換に使用されるコンテンツ形式を決定することができます。

このタスクについて

リソースはさまざまな形式でデータを表示できます。 URL、要求パラメーター、または HTTP ヘッダーに基づいたコンテンツ・ネゴシエーションを実装できます。 このタスクでは、さまざまなデータ形式を送信および受信するための、HTTP Accept ヘッダーに基づいた コンテンツ・ネゴシエーションについて説明します。

Web ブラウザーは、要求を行う際に、何を求めているのかについての情報をヘッダーに入れてサーバーに送信します。 それらのヘッダーの 1 つが Accept ヘッダー です。 Accept ヘッダーは、クライアントがどのような形式 または MIME タイプを予期しているのかをサーバーに知らせます。 HTTP Accept ヘッダー を使用して、データ交換に使用されるコンテンツ形式を判定できます。

Accept ヘッダー は URL やパラメーターのように可視ではありませんが、このヘッダー を使用する方式は、コンテンツ・ネゴシエーションをより柔軟に扱うことができます。 また、HTTP AcceptAccept-CharsetAccept-Language 、 そしてAccept-Encodingヘッダーによって、サーバーから返されるコンテンツの種類が決まります。

HTTP Accept ヘッダーを使用して、受け入れ可能な応答について、 それがどの程度の質で受け入れ可能なのかを割り当てることができます。 例えば、あるクライアント は、優先されるコンテンツ・タイプとして XML を指示できます。 ただし、XML が 使用可能でない場合、そのクライアントが JSON またはプレーン・テキスト形式を受け入れるようにできます。

例えば、 Accept ヘッダーに application/json; q=1.0, text/xml;q=0.5, application/xml;q=0.5 のような値が入っている場合、 この値は、優先されるのは JSON だが、XML も受け入れ可能であることを示しています。

他のコンテンツ・ネゴシエーション方式 では、優先応答タイプは 1 つしかないのが 普通です。 しかし、HTTP Accept ヘッダーを 使用すると、クライアントが受け入れ可能なタイプを 1 つの要求内にすべて網羅して、 サービスに通知することができます。 さらに、HTTP Accept ヘッダーおよびその関連ヘッダー は、HTTP 標準の一部です。

HTTP ヘッダーを使用するコンテンツ・ネゴシエーションを 実装するときには、以下の観点から検討をすることが 重要です。 正しくない値を送信するクライアントや、 Accept HTTP ヘッダーに注意を払わないサービスがある場合もあります。 また、 すべての HTTP ヘッダーを処理し、最適な応答を計算することは、 URL または要求パラメーターに基づくコンテンツ要求ほど単純では ありません。

手順

  1. 追加@javax.ws.rs.core.Context javax.ws.rs.core.Requestリソース メソッドへのパラメーター。
  2. 使用javax.ws.rs.core.Variant.VariantListBuilderサービスがサポートする可能性のある応答バリアントのリストを作成するオブジェクト。
  3. 受け入れ可能な応答をテストします。

    javax.ws.rs.core.Request.selectVariant(java.util.List<Variant>variant) メソッド を使用して、クライアントに送信するための受け入れ可能な応答を受け取るかどうかを 判別します。 考えられるすべての応答のバリアントのリストが、このメソッドに渡されます。 各バリアントは、メディア・タイプ、言語、およびエンコード方式の組み合わせを 1 つ表します。 バリアント・リストの作成について詳しくは、javax.ws.rs.core.Variant および javax.ws.rs.core.Variant.VariantListBuilder API 文書 を参照してください。

    応答バリアントのリストおよび着信要求 HTTP ヘッダーに基づいて、 selectVariant(java.util.List<Variant> variant) メソッド は、HTTP ヘッダーに一致する最高の応答バリアントを戻します。

    以下は、javax.ws.rs.core.Request タイプを 注入して @javax.ws.rs.core.Context アノテーションを使用して 判別する例です。 javax.ws.rs.core.Request タイプは、最適の応答バリアントを判別するのに役立ちます。 この例では、リソース・メソッドが呼び出されると、ランタイム環境によって要求オブジェクトが 渡されます。
    @Path("/resources")
    public class Resource
    {
        @Path("{resourceID}")
        @GET
        public Response getResource(@PathParam("resourceID") String resourceID, @Context Request req)
        {
            /* This method builds a list of possible variants. */
            /* You must call Variant.VariantListBuilder.add() object before calling the Variant.VariantListBuilder.build() object. */
            List<Variant> responseVariants =
                     Variant
                         .mediaTypes(
                                     MediaType.valueOf(MediaType.APPLICATION_XML + ";charset=UTF-8"),
                                     MediaType.valueOf(MediaType.APPLICATION_XML + ";charset=shift_jis"),
                                     MediaType
                                         .valueOf(MediaType.APPLICATION_JSON))
                         .encodings("gzip", "identity", "deflate").languages(Locale.ENGLISH,
                                                                             Locale.FRENCH,
                                                                             Locale.US).add().build();
    
              /* Based on the Accept* headers, an acceptable response variant is chosen.  If there is no acceptable variant,
              selectVariant will return a null value. */
    
             Variant bestResponseVariant = req.selectVariant(responseVariants);
             if(bestResponseVariant == null) {
    
                 /* Based on results, the optimal response variant can not be determined from the list given.  */ 
    
                return Response.notAcceptable().build();
             }
             MediaType responseMediaType = bestResponseVariant.getMediaType();
    
             /* This instruction obtains the acceptable language and modifies the response entity. */
    
             Locale responseLocale = bestResponseVariant.getLanguage();
             if(responseMediaType.isCompatible(MediaType.APPLICATION_XML_TYPE)) {
                 return Response.ok(/* entity in XML format */).type(MediaType.APPLICATION_XML).build();
             } else if (responseMediaType.isCompatible(MediaType.APPLICATION_JSON_TYPE)) {
                 	return Response.ok(/* The entity is  in JSON format */)
    
    				.type(MediaType.APPLICATION_JSON).build();
             }
             return Response.notAcceptable(Variant.mediaTypes(MediaType.APPLICATION_XML_TYPE,
    				 MediaType.APPLICATION_JSON_TYPE).add().build()).build();
         }
     }

結果

データを表示するリソース形式を Accept ヘッダーを使用して決定する、 コンテンツ・ネゴシエーションの実装が完了しました。