11

コンテンツ タイプのさまざまなバージョンを処理するために、「Accept*」ヘッダー ( RFC 2616 ) の accept-parameters を使用しようとしています。

Accept: application/vnd.mycompany.mytype;version=2 , application/vnd.mycompany.mytype;version=1;q=0.1

問題は、Jax-RS アノテーションが Accept-parameters をサポートしていないことです...

@GET
@Produces("application/vnd.test;version=1")
public Response test1() {
    return Response.ok("Version 1", "application/vnd.test").build();
}

@GET
@Produces("application/vnd.test;version=2")
public Response test2() {
    return Response.ok("Version 2", "application/vnd.test").build();
}

メディア タイプの競合の例外が発生します。

Producing media type conflict. The resource methods public javax.ws.rs.core.Response test.resources.TestResource.test2() and public javax.ws.rs.core.Response test.resources.TestResource.test1() can produce the same media type

おそらく、この例外は私の JAX-RS フレームワーク (Jersey) にのみ関連していますが、accept-parameters について明示されていないJSR311が原因ではないかと心配しています。

今では、名前にバージョンを保持するコンテンツタイプを使用していますが、このソリューションはかなり醜いことがわかりました。

@GET
@Produces("application/vnd.test-v1")
public Response test() {
    return Response.ok("Version 1", "application/vnd.test-v1").build();
}

accept-parameters を処理する方法について何か考えはありますか?

編集

私は十分に明確ではなかったと思います。リクエストを特定のメソッドに自動的にルーティングしたい。これらのメソッドはバージョン管理されており、返されるコンテンツ タイプの特定のバージョンに対応しています。JAX-RS の現在の実装では、accept-parameters を使用してリクエストを (対応するメソッドに) ルーティングすることができません。

greenkode はversion、ディスパッチ メソッド内で accept-parameter を管理することを提案します (を使用@HeaderParam("Accept"))。このソリューションは、フレームワークに組み込まれている (そして JSR 311 で説明されている) コンテンツ ネゴシエーション ロジックを書き直すことになります。

JAX-RS の accept-parameter と content-negociation ロジックの両方を使用するにはどうすればよいですか?

おそらく解決策は、別のフレームワークを使用することです(私は今のところJerseyのみを使用していました)。でもどっちか分からない。

4

3 に答える 3

16

JAX-RS 仕様では、 Accept ヘッダー パラメータを無視することについて明示的に述べていません。しかし、取り扱いが明確に定義されている唯一のパラメーターは品質(q) です。これは、Jersey の実装であいまいさ (または完全なバグ) につながっているように見えるため、改善が必要な領域です。Jersey (1.17) の現在のバージョンでは、受信リクエストをリソース メソッドに一致させる際に Accept ヘッダー パラメータが考慮されていないため、次のエラーが発生します。

SEVERE: メディア タイプの競合が発生しています。リソースメソッド...

リソースの場合:

@GET
@Produces("application/vnd.test;version=1")
public Response test1() {
    return Response.ok("Version 1", "application/vnd.test").build();
}

@GET
@Produces("application/vnd.test;version=2")
public Response test2() {
    return Response.ok("Version 2", "application/vnd.test").build();
}

Jersey は、Accept ヘッダーの「タイプ/サブタイプ」に基づいて「一意性」チェックを実行し、パラメーターを完全に省略しているように見えます。これは、「一致する」リソース メソッドでさまざまなヘッダーのペアをテストすることで確認できます。

リソース 1 リソース 2
--------------------------------------------
テキスト/html;q=0.4 テキスト/html;q=0.8
テキスト/html テキスト/html;q=0.2
テキスト/html テキスト/html;qs=1.4
テキスト/html;qs=1.4 テキスト/html;qs=1.8
テキスト/html;レベル=1 テキスト/html;レベル=2
text/html;foo=bleh text/html;bar=23

すべて同じエラーで失敗します。品質パラメーターのみが送信されると仮定した場合、この種の要求は無意味であるため、「タイプ/サブタイプ」でのみ一致することが理にかなっています。

受け入れる: text/html;q=0.8, text/html;q=0.4, text/html

別名、品質パラメーターは、考えられるコンテンツ タイプが混在している場合にのみ意味があります。ただし、非品質パラメータまたは追加パラメータが送信されている場合、この種の限定的なマッチングは失敗します。

受け入れる: text/html;version=4.0;q=0.8, text/html;version=3.2;q=0.4

では、可能な解決策は何ですか?

  • 「タイプ/サブタイプ」に基づいて高レベルのリクエストを傍受し、より適切な方法にルーティングします(これを行いたくないことを示しています)
  • 予想されるヘッダーを変更します。たとえば、'application/vnd.mycompany.mytype+v2' および 'application/vnd.mycompany.mytype+v1' です。他の変更は必要なく、Jersey を使い続けることができます
  • フレームワークを切り替えます。RESTEasyはたまたまシナリオを簡単に処理します。

RESTEasy とリソースを使用:

@Path("/content/version")
public class ContentVersionResource {

    @GET
    @Produces("application/vnd.test;version=1")
    public Response test1() {
        return Response.ok("Version 1", "application/vnd.test").build();
    }

    @GET
    @Produces("application/vnd.test;version=2")
    public Response test2() {
        return Response.ok("Version 2", "application/vnd.test").build();
    }
}

次の Accept ヘッダーで一致が成功します。

受け入れ: application/vnd.test;version=1;q=0.3, application/vnd.test;version=2;q=0.5
応答: バージョン 2

この:

受け入れ: application/vnd.test;version=1;q=0.5, application/vnd.test;version=2;q=0.3
応答: バージョン 1

このサンプル プロジェクトをダウンロードしてテストできます。Git、Maven、および JBoss 7.x が必要

于 2013-04-17T02:57:06.983 に答える
1

Jersey フレームワークでは、HTTP 要求の Accept ヘッダーが最も受け入れられるものを宣言していました。リソース クラスが複数の MIME メディア タイプを生成できる場合、選択されたリソース メソッドは、クライアントによって宣言された最も受け入れ可能なメディア タイプに対応します。あなたの場合、受け入れヘッダーが

Accept: application/vnd.mycompany.mytype;version=2

次に、メソッド test1() が呼び出されます。

もしそれが

Accept: application/vnd.mycompany.mytype;q=0.9 version=2, application/vnd.mycompany.mytype;version=1

後者が呼び出されます。

同じ @Produces 宣言で複数のメディア タイプを宣言できます。次に例を示します。

@GET
@Produces({"application/vnd.mycompany.mytype; version=2", "application/vnd.mycompany.mytype; version=1"})
public Response test() {
    return Response.ok("").build();
}

2 つのメディアタイプのいずれかが受け入れられる場合、test(9 メソッドが呼び出されます。両方が受け入れられる場合、最初のものが呼び出されます。

それが役に立てば幸い!

于 2013-04-16T11:55:14.650 に答える