jsonp Cross-Domain Request Details - From Complex to Simple
Original Link: https://zhuanlan.zhihu.com/p/24390509
Detailed description of the origin and evolution of cross-domain requests - shared by hinesboy
What is jsonp?Why use jsonp?
JSONP(JSON with Padding) is a "usage mode" of JSON that can be used to solve cross-domain data access problems in mainstream browsers.Due to homology policy, web pages located in server1.example.com generally cannot communicate with servers that are not server1.example.com, while HTML's
$.get("http://169.254.200.238:8080/jsonp.do", function (data) {
console.log(data);
});
The browser threw an exception at this time
Because the port numbers 8080 and 8020 are not the same origin, we can also see from the error.
However, we request in a different way:
<script type="text/javascript" src="http://169.254.200.238:8080/jsonp.do">
</script>
You can see that at this point the same request really succeeded!From this, we can conclude that cross-domain requests can be made, which is the basis of jsonp, but the browser also throws an exception with an illegal statement.
That's because the data we're requesting is immediately executed by the browser as a javascript statement (who lets us use it)
callback( {"result":"success"} )
Where {"result": "success"} is the data we want to get, the browser will immediately execute the callback function, at this time, we have defined the function called callback:
function callback(data){
// Data returns data
// TODO parsing data
}
Is that all right?
So the key to jsonp cross-domain requests is:
The server wraps a client-defined function around the returned data
ajax cross-domain request instance
Understanding the above, you already know the principle of cross-domain requests, so below we will use ajax to initiate cross-domain requests, and the server will process jsonp requests through spring MVC.
//Initiate jsonp request through JQuery Ajax
(Note: It is not necessary to pass jq Initiate Request ,
//For example, $.http.jsonp(url, [options]) is provided in the Vue Resource
$.ajax({
// Request Method
type: "get",
// Request Address
url: "http://169.254.200.238:8080/jsonp.do",
// Flag cross-domain request
dataType: "jsonp",
// The key value for the cross-domain function name, which is the key for the server to extract the function name (callback by default)
jsonp: "callbackparam",
// Function name agreed upon between client and server
jsonpCallback: "jsonpCallback",
// A successful callback function was requested, and json is both the data we want to get
success: function(json) {
console.log(json);
},
// Callback function for request failure
error: function(e) {
alert("error");
}
});
@RequestMapping({"/jsonp.do"})
public String jsonp(@RequestParam("callbackparam") String callback){
// callback === "jsonpCallback"
return callback + "({\"result\":\"success\"})";
}
At this point, the return value received by the client is:
This is a complete cross-domain request, but is it over?
Careful classmates may find that if you don't request the jsonp.do interface across domains now, you're wrong?
Yes, at present this interface can only be requested with the parameter callbackparam.
To solve this problem, we need to determine the source of the request.
return (request.from === jsonp) ? callback(data) : data ;
That's what we want, and solving this problem requires us to make a judgment on each interface, or to achieve uniform processing through AOP and so on, which is not elegant.
CORS (Cross-domain Resource Sharing) is supported in spring4.2 and above
CORS
CORS is a W3C standard, the full name is Cross-origin resource sharing.
It allows browsers to issue XMLHttpRequest requests to cross-source servers, overcoming the limitation that AJAX can only be used from the same source.
Why is it elegant?
The whole CORS communication process is completed automatically by the browser without user participation.For developers, CORS communication is not different from the same source AJAX communication, and the code is exactly the same.Once the browser finds that the AJAX request is cross-source, it will automatically add some additional header information and sometimes an additional request, but the user will not feel it.
Therefore, the key to CORS communication is the server.As long as the server implements the CORS interface, it can communicate across sources.
So our clients can send our requests as if nothing happened:
// Don't worry about cross-domain issues
$.ajax({
// Request Method
type: "get",
// Request Address
url: "http://169.254.200.238:8080/jsonp.do",
// Request data in json format instead of jsonp at this time
dataType: "json",
// Callback function with successful request
success: function(json) {
console.log(json);
},
// Callback function for request failure
error: function(e) {
alert("error");
}
});
The server side we implemented with spring MVC was unexpectedly concise (based on xml):
// Spring profile spring must be at least version 4.2
<mvc:cors>
<mvc:mapping path="/**" />
</mvc:cors>
Note: We have completed the cross-domain request operation through the above two steps.
Here, I've added cross-domain support for the whole project. To support cross-domain path s, you can also configure it here in detail:
<mvc:cors>
<mvc:mapping path="/api/**"
allowed-origins="http://domain1.com, http://domain2.com"
allowed-methods="GET, PUT"
allowed-headers="header1, header2, header3"
exposed-headers="header1, header2" allow-credentials="false"
max-age="123" />
<mvc:mapping path="/resources/**"
allowed-origins="http://domain1.com" />
</mvc:cors>
Of course, spring also supports configuration in java:
// This is equivalent to xml global configuration
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
}
// This is a detailed configuration
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("http://domain2.com")
.allowedMethods("PUT", "DELETE")
.allowedHeaders("header1", "header2", "header3")
.exposedHeaders("header1", "header2")
.allowCredentials(false).maxAge(3600);
}
}
Prig also allows for cross-domain manipulation of a controller class or method through the @Configuration annotation.
There is no detailed explanation here. Details can be referred to
SpringMvc Solves Cross-domain Problems - Wang Nian Blog - Open Source Chinese Community