1. 概述
如果您在Web上開發過任何東西,您應該知道瀏覽器在處理AJAX請求時所遵循的同源策略。該策略的簡單概述是,來自不同域、方案或端口的任何請求均將被拒絕。
一種放鬆瀏覽器限制的方法,用於處理JSON數據,是使用JSON with padding(JSON-P)。
本文討論了Spring對處理JSON-P數據(藉助AbstractJsonpResponseBodyAdvice)的支持。
2. JSON-P in Action
The same-origin policy is not imposed over the <script> tag, allowing scripts to be loaded across different domains. JSON-P technique takes advantage of this by passing the JSON response as the argument of the javascript function.
2.1. Preparation
In our examples, we will use this simple Company class:
public class Company {
private long id;
private String name;
// standard setters and getters
}
This class will bind the request parameters and shall be returned from the server as JSON representation.
The Controller method is a simple implementation as well – returning the Company instance:
@RestController
public class CompanyController {
@RequestMapping(value = "/companyRest",
produces = MediaType.APPLICATION_JSON_VALUE)
public Company getCompanyRest() {
Company company = new Company(1, "Xpto");
return company;
}
}
On the client side we can use jQuery library to create and send an AJAX request:
$.ajax({
url: 'http://localhost:8080/spring-mvc-java/companyRest',
data: {
format: 'json'
},
type: 'GET',
...
});
Consider an AJAX request against the following URL:
http://localhost:8080/spring-mvc-java/companyRest
The response from the server would be the following:
{"id":1,"name":"Xpto"}
As the request was sent against the same schema, domain, and port, the response will not get blocked, and JSON data will be allowed by the browser.
2.2. Cross-Origin Request
By changing the request URL to:
http://127.0.0.1:8080/spring-mvc-java/companyRest
the response will get blocked by the browser, due to request being sent from localhost to 127.0.0.1 which is considered a different domain and presents a violation of the same-origin policy.
With JSON-P, we are able to add a callback parameter to the request:
http://127.1.1.1:8080/spring-mvc-java/companyRest?callback=getCompanyData
On the client side it’s as easy as adding the following parameters to the AJAX request:
$.ajax({
...
jsonpCallback:'getCompanyData',
dataType: 'jsonp',
...
});
The getCompanyData will be the function called when the response is received.
If the server formats the response like the following:
getCompanyData({"id":1,"name":"Xpto"});
browsers will not block it, as it will treat the response as a script negotiated and agreed upon between the client and the server on account of matching getCompanyData in both request and the response.
@ControllerAdvice 註定的 Bean 能夠幫助所有或特定子集 Controller,並用於封裝不同 Controller 之間共享的橫切關注點。 典型的用法與異常處理、為模型添加屬性或註冊 Binder 相關。
從 Spring 4.1 開始,@ControllerAdvice 能夠註冊 ResponseBodyAdvice 接口的實現,這允許在控制器方法返回後,但在合適的轉換器寫入之前更改響應。
4. 使用 AbstractJsonpResponseBodyAdvice 進行響應更改
Also starting with Spring 4.1, we now have access to the AbstractJsonpResponseBodyAdvice class – which formats the response according to JSON-P standards.
This section explains how to put the base class at play and change the response without making any changes to the existing Controllers.
In order to enable Spring support for JSON-P, let’s start with the configuration:
@ControllerAdvice
public class JsonpControllerAdvice
extends AbstractJsonpResponseBodyAdvice {
public JsonpControllerAdvice() {
super("callback");
}
}
The support is made using the AbstractJsonpResponseBodyAdvice class. The key passed on the super method is the one that will be used in URL requesting JSON-P data.
With this controller advice, we automatically convert the response to 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 的過程,否則這項工作本身就十分繁瑣。