1. 概要

Webで何かを開発している場合は、同一生成元ポリシーの制約ブラウザーがAJAX要求を処理するときに持っていることを知っています。 制約の簡単な概要は、異なるドメイン、スキーマ、またはポートから発信された要求は許可されないということです。

JSONデータを操作するときにこのブラウザー制限緩和する1つの方法は、パディング付きのJSON( JSON-P )を使用することです。

この記事では、 AbstractJsonpResponseBodyAdvice を使用して、JSON-Pデータを操作するためのSpringのサポートについて説明します。

2. JSON-Pの動作

同一生成元ポリシーは、 tag, allowing scripts to be loaded across different domains. JSON-P手法は、JavaScript関数の引数としてJSON応答を渡すことにより、これを利用します。

2.1. 準備

この例では、次の単純なCompanyクラスを使用します。

public class Company {
 
    private long id;
    private String name;
 
    // standard setters and getters
}

このクラスはリクエストパラメータをバインドし、JSON表現としてサーバーから返されます。

Controllerメソッドも単純な実装であり、Companyインスタンスを返します。

@RestController
public class CompanyController {

    @RequestMapping(value = "/companyRest",
      produces = MediaType.APPLICATION_JSON_VALUE)
    public Company getCompanyRest() {
        Company company = new Company(1, "Xpto");
        return company;
    }
}

クライアント側では、 jQuery ライブラリを使用して、AJAXリクエストを作成して送信できます。

$.ajax({
    url: 'http://localhost:8080/spring-mvc-java/companyRest',
    data: {
        format: 'json'
    },
    type: 'GET',
    ...
});

次のURLに対するAJAXリクエストについて考えてみます。

http://localhost:8080/spring-mvc-java/companyRest

サーバーからの応答は次のようになります。

{"id":1,"name":"Xpto"}

リクエストは同じスキーマ、ドメイン、ポートに対して送信されたため、レスポンスはブロックされず、JSONデータはブラウザーで許可されます。

2.2. クロスオリジンリクエスト

リクエストURLを次のように変更します。

http://127.0.0.1:8080/spring-mvc-java/companyRest

localhostから127.0.0.1にリクエストが送信されたため、応答はブラウザによってブロックされます。これは、別のドメインと見なされ、同一生成元ポリシーに違反しています。

JSON-Pを使用すると、リクエストにコールバックパラメーターを追加できます。

http://127.1.1.1:8080/spring-mvc-java/companyRest?callback=getCompanyData

クライアント側では、AJAXリクエストに次のパラメータを追加するのと同じくらい簡単です。

$.ajax({
    ...
    jsonpCallback:'getCompanyData',
    dataType: 'jsonp',
    ...
});

getCompanyData は、応答を受信したときに呼び出される関数になります。

サーバーが応答を次のようにフォーマットする場合:

getCompanyData({"id":1,"name":"Xpto"});

リクエストとレスポンスの両方でgetCompanyDataが一致するため、クライアントとサーバー間でネゴシエートおよび合意されたスクリプトとしてレスポンスを処理するため、ブラウザはそれをブロックしません。

3. @ControllerAdviceアノテーション

@ControllerAdvice で注釈が付けられたBeanは、コントローラーのすべてまたは特定のサブセットを支援することができ、異なるコントローラー間で共有される横断的な動作をカプセル化するために使用されます。 一般的な使用パターンは、例外処理モデルへの属性の追加、またはバインダーの登録に関連しています。

Spring 4.1 以降、 @ControllerAdvice は、 ResponseBodyAdvice インターフェイスの実装を登録できます。これにより、コントローラーメソッドによって返される前に、応答を変更できます。適切なコンバータによって書かれました。

4. AbstractJsonpResponseBodyAdviceを使用して応答を変更する

また、Spring 4.1 から、AbstractJsonpResponseBodyAdviceクラスにアクセスできるようになりました。このクラスはJSON-P標準に従って応答をフォーマットします。

このセクションでは、既存のコントローラーに変更を加えずに、基本クラスを実行して応答を変更する方法について説明します。

SpringによるJSON-Pのサポートを有効にするために、構成から始めましょう。

@ControllerAdvice
public class JsonpControllerAdvice 
  extends AbstractJsonpResponseBodyAdvice {

    public JsonpControllerAdvice() {
        super("callback");
    }
}

サポートは、AbstractJsonpResponseBodyAdviceクラスを使用して行われます。 スーパーメソッドに渡されるキーは、JSON-Pデータを要求するURLで使用されるキーです。

このコントローラーのアドバイスにより、応答を自動的にJSON-Pに変換します。

5. 春のJSON-Pが実際に

前述の構成を適切に行うことで、RESTアプリケーションをJSON-Pで応答させることができます。 次の例では、会社のデータを返すため、AJAXリクエストURLは次のようになります。

http://127.0.0.1:8080/spring-mvc-java/companyRest?callback=getCompanyData

以前の構成の結果、応答は次のようになります。

getCompanyData({"id":1,"name":"Xpto"});

説明したように、この形式の応答は、別のドメインから発信されているにもかかわらずブロックされません。

JsonpControllerAdvice は、@ResponseBodyおよびResponseEntityで注釈が付けられた応答を返す任意のメソッドに簡単に適用できます。

すべての応答を処理するために、コールバックで渡される同じ名前の関数getCompanyDataが必要です。

6. 結論

この簡単な記事では、Spring 4.1の新機能を使用して、JSON-Pを利用するために応答をフォーマットするという面倒な作業がどのように簡素化されるかを示します。

例とコードスニペットの実装は、このGitHubプロジェクトにあります。