1. 概述
如果您在Web上進行過任何開發,您應該知道瀏覽器在處理AJAX請求時所遵循的同源策略。該策略的簡單概述是,來自不同域、協議或端口的任何請求都將被拒絕。
使用JSON填充(JSON-P)來緩解瀏覽器限制的一種方法是使用JSON-P。
本文討論了Spring對使用JSON-P數據(藉助AbstractJsonpResponseBodyAdvice)的支持。
2. JSON-P in Action
相同的源站策略並不會應用於<script>標籤,允許腳本在不同域之間加載。JSON-P 技術利用了這一點,通過將 JSON 響應作為 JavaScript 函數的參數傳遞。
2.1. 準備
在我們的示例中,我們將使用這個簡單的 Company 類:
public class Company {
private long id;
private String name;
// standard setters and getters
}
此類將綁定請求參數,並從服務器端返回以 JSON 格式表示的結果。
控制器方法是一個簡單的實現——返回 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 能夠輔助所有或特定子集 Controller,並用於封裝不同 Controller 之間共享的橫切關注點。 典型的用法與異常處理、為模型添加屬性或註冊 Binder 相關。
從 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. 使用 Spring 實現 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 的過程。