Spring handles cross-domain requests

Source: Internet
Author: User

[Nio-8080-exec-8] O.s.web.cors.defaultcorsprocessor:skip cors processing:request is from same origin a normal request

Recently someone needs to call a feature of our system and the other person wants to provide an API to update the data. Since the classmate is a client-side developer, there is a code similar to the following.

  @RequestMapping (method = requestmethod.post, value =  "/ Update.json ", produces = mediatype.application_json_value) public  @ResponseBody Contacter Update ( @RequestBody contacter Contacterro) { Logger. Debug ( "get update request {}", contacterro.tostring ());  if (contacterro.getuserid () = = 123) {contacterROsetusername ( "Adminupdate-wangdachui");} return contacterro;}      

The client invokes the HTTP request through the code. Then, the classmate also put forward: hope to use the browser JS call, so there is a cross-domain problem.

Why cross-domain

Simply put, the browser restricts access to the JS code under Site A to make an AJAX request to the URL under Site B. If the current domain name is www.abc.com, then in the current environment to run the JS code, for security reasons, under normal circumstances can not access the resources under the www.zzz.com domain name.

    • For example: The following code in this domain name can be properly called through the JS code interface
(function () {var url = "Http://localhost:8080/api/Home/update.json"  "userId": 123,  "UserName ": " Wangdachui "}; $.ajax ({url:url, type:  ' POST ', DataType:  ' json ', Data: $.tojson ( data), ContentType:  ' Application/json '}). Done ( function (result) {console.log (result) function () {Console.log ( "error") < /span>  

The output is:

Object {userId: 123, userName: "adminUpdate-wangdachui"}
    • However, there is an error accessing the other domain name:

load http://localhost:8080/api/Home/update.json. Response to preflight request doesn‘t pass access control check: No ‘Access-Control-Allow-Origin‘ header is present on the requested resource. Origin ‘null‘ is therefore not allowed access. The response had HTTP status code 403.
Solution Jsonp

The use of Jsonp to cross-domain is a common way, but in the case of the interface has been written, both the server and the caller need to be modified and to be compatible with the original interface, the workload is too large, so we consider other methods.

Cors protocol

According to reference, each page needs to return an HTTP header named ' Access-control-allow-origin ' to allow access to other sites. You can only expose limited resources and limited access to the extranet sites. In Cor mode, the responsibility for access control can be placed in the hands of the page developer, not the server administrator. Of course page developers need to write special processing code to allow access by the other. We can understand that if a request needs to allow cross-domain access, you need to set Access-control-allow-origin in the HTTP header to determine which sites need to be allowed to access. If you need to allow www.foo.com requests across domains for this site, you can set: Access-control-allow-origin:http://www.foo.com. or Access-control-allow-origin: *. Cors, as part of HTML5, is supported in most modern browsers.

Cors has the following common headers
access-control-allow-origin:http://foo.orgaccess-control-max-age:3628800access-control-allow-methods:get,put, DELETEaccess-control-  Allow-headers: content-type"Access-control-allow-origin" indicates that it allows " http://foo.org" to initiate cross-domain requests " Access-control-max-age "indicates that, within 3.6288 million seconds, no pre-test request can be sent and the result " Access-control-allow-methods "is cached to indicate that it allows GET, The otherrequest "access-control-allow-headers" of the PUT and delete indicates that it allows the cross-domain request to contain the content-type header   
Cors Basic Process

First issue a pre-test (preflight) request, which first issues a options method to the resource server, containing the "Origin" header request. The reply can control the method of the COR request, the HTTP header, and the authentication information. A real-world request will be initiated only if the request has been allowed.

Spring MVC supports Cors
check: No ‘Access-Control-Allow-Origin‘ header is present on the requested resource. Origin ‘null‘ is therefore not allowed access. The response had HTTP status code 403.

As we can see from the above error message, the direct reason is that there is no access-control-allow-origin this header in the request header. So our direct idea is to add the header to the request. The server is able to return 403, indicating that the server is indeed processing the request.

MVC Interceptor

First we configure an interceptor to intercept the request and log the requested header information.

DEBUGRequesturl:/api/home/update.json DEBUGMethod:options DEBUG HeaderHostlocalhost8080 Debug header connection:keep-alive Debug Header Cache-control:max-age=0 DEBUG header Access-control-request-method:post Debug header origin:null Debug Header User-agent:mozilla/5.0 (Windows NT 6.1; WOW64) Applewebkit/537.36 (khtml, like Gecko) Chrome/ 49.0.2623.87 safari/537.36 DEBUG header access-control-request- headers:accept, Content-type DEBUG header accept:*/* Debug Header Accept-encoding:gzip, deflate, SDCH debug Header accept-language:zh-cn,zh;q=0.8,en;q=0.6 

Print logs found in Posthandle, at which point the status of response is 403. Trace Springmvc Code Discovery, In Org.springframework.web.servlet.DispatcherServlet.doDispatch, the HANDLEREXECUTIONCHAIN,SPRINGMVC will be checked based on request to obtain a regular processor. is a cross-domain request and, if it is, replaces the existing instance.

@OverridepublicFinal Handlerexecutionchain GetHandler (HttpServletRequest request) throws Exception {Object handler = gethandlerinternal (request);if (handler = =NULL) {handler = Getdefaulthandler ();}if (handler = =NULL) {Returnnull;} //Bean name or resolved handler? if (handler instanceof string) { string handlerName = (string) Handler;handler = Getapplicationcontext (). Getbean (HandlerName);} Handlerexecutionchain Executionchain = Gethandlerexecutionchain (handler, request); if (corsutils.iscorsrequest (Request)) {Corsconfiguration GlobalConfig = this.corsconfigsource.getcorsconfiguration (Request); Corsconfiguration handlerconfig = getcorsconfiguration (handler, request); corsconfiguration config = (globalconfig! = null? Globalconfig.combine (HandlerConfig): Handlerconfig); executionchain = Getcorshandlerexecutionchain (request, Executionchain, config);} return Executionchain;}          

The

Check method is also simple, which is to check the request header for an Origin field

  public static  boolean iscorsrequest (httpservletrequest request< Span class= "Hljs-params" >)  {return (Request.getheader ( Httpheaders.origin)! = null);           

The request is then referred to Httprequesthandleradapter.handle to handle different logic depending on the handle. The front is based on the request header is a cross-domain request, obtained handler for Preflighthandler, in fact, is now:

@OverridePublic void HandleRequest(httpservletrequest request, httpservletresponse response)  throws  ioexception { Corsprocessor.processrequest (this.config, request, response);}      

Continue to follow up

@Overridepublic boolean ProcessRequest (corsconfiguration config, httpservletrequest request, httpservletresponse response) Throws IOException {if (! Corsutils.iscorsrequest (Request)) {Returntrue;} Servletserverhttpresponse serverresponse = new Servletserverhttpresponse (response); Servletserverhttprequest serverrequest = new Servletserverhttprequest (request);if (Webutils.issameorigin (serverrequest)) {Logger.debug ("Skip CORS processing, request is a same-origin one");return true;} if (responsehascors (serverresponse)) {Logger.debug ( "Skip CORS processing, response already contains \ "access-control-allow-origin\" header "); return true;} Boolean preflightrequest = corsutils.ispreflightrequest (request); if (config = null) {if ( Preflightrequest) {rejectrequest (serverresponse);  return FALSE;} else {return true;} return handleinternal (serverrequest, serverresponse, config, preflightrequest);}   

This method first checks if it is a cross-domain request, if it is not, returns directly, and then checks whether the same domain Or if the response header has a access-control-allow-origin field or if the Request has access-control-request-method. If the judgment condition is met, the request is rejected. From this we know that you can pass the check by setting the Access-control-allow-origin header of the response before checking. We are dealing with the prehandle of the Interceptor. Add the following code:

response.setHeader("Access-Control-Allow-Origin", "*");

The options request in the browser returns 200. But still the error:

Request header field Content-Type is not allowed by Access-Control-Allow-Headers in preflight response.

We note that there is access-control-request-headers:accept in the request header, Content-type, but not in the request headers, when the browser does not have to send the request. Try to include in response:

response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");

Execution succeeded: Object {userid:123, userName: "Adminupdate-wangdachui"}.

So far: We have analyzed the principle to enable SPRINGMVC to achieve cross-domain, the original implementation and the client code does not need any changes.

SPRINGMVC 4
    • In addition, in reference 2, SPRINGMVC4 provides a very convenient way to implement a cross-domain approach.
    • Use annotations in requestmapping. @CrossOrigin (Origins = "http://localhost:9000")
    • Global implementation. Defining Class Inheritance Webmvcconfigureradapter
class CorsConfigurerAdapter extends WebMvcConfigurerAdapter{@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/api/*").allowedOrigins("*");}}

Inject the class into the container:

class="com.tmall.wireless.angel.web.config.CorsConfigurerAdapter"></bean>
Resources
    • Cross-origin resource Sharing
    • Enabling cross Origin requests for a RESTful Web Service

Spring handles cross-domain requests

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.