Error: No ‘access-Control-allow-origin’ header is present on the requested resource

This is due to Ajax cross-domain requests

What is cross-domain

Due to the browser same origin policy (the same origin policy, it is a well-known security policy introduced by Netscape. This strategy is now used by all browsers that support JavaScript. The so-called homology refers to the same domain name, protocol, and port), any protocol, domain name, or port that sends the request URL is different from the current page address, that is, cross-domain.

How does it works ?

CORS requests (including pre-selected methods with options) are automatically registered with various HandlerMapping. They process CROS preparation requests and intercept CORS simple and actual requests, thanks to the CorsProcessor implementation (default DefaultCorsProcessor processor), To add relevant CORS response headers (such as access-Control-Allow-Origin). CorsConfiguration allows you to specify how CORS requests should be handled: Allow origins, HEADERS, methods, and so on.

AbstractHandlerMapping#setCorsConfiguration() allows you to specify a mapping where several corsConfigurations are mapped to the path pattern, e.g. / API /**.

B. Subclasses can provide CorsConfiguration by overriding getCorsConfiguration(Object, HttpServletRequest) of the AbstractHandlerMapping class.

C, the handler can realize CorsConfigurationSource interface (e.g., ResourceHttpRequestHandler), in order to provide a CorsConfiguration for each request.

How to solve

Common cross-domain request solution

@crossorigin (origins = “*”, maxAge = 3600)

Note: “*” origins = “origins” specifies the domain in which the interface is currently requested

2. General configuration

/** * @author chendesheng * @create 2019/9/16 19:07 */ @configuration public class CorsConfig {@bean public CorsFiltercorsFilter(){
            UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
            source.registerCorsConfiguration("/ * *",buildconfig());
            return new CorsFilter(source);
        }
    
        private CorsConfiguration buildconfig(){
            CorsConfiguration corsConfiguration = new CorsConfiguration();
            corsConfiguration.addAllowedOrigin("*");
            corsConfiguration.addAllowedHeader("*");
            corsConfiguration.addAllowedMethod("*");
            returncorsConfiguration; }}Copy the code

Ajax customizes cross-domain requests for HEADERS

    $.ajax({
            type:"GET",
            url:"http://localhost:8766/main/currency/sginInState",
            dataType:"JSON",
            data:{
                uid:userId
            },
            beforeSend: function (XMLHttpRequest) {
                XMLHttpRequest.setRequestHeader("Authorization", access_token);
            },
            success:function(res){
                console.log(res.code)
            }
        })
Copy the code

Here to request an error: OPTIONS http://localhost:8766/main/currency/sginInState 500

Common cross-domain solutions can no longer solve this problem. Why do OPTIONS requests appear?

The reason:

But are not all requests sent, but they have to do the following: are not all requests known but are known as Preflighted requests

  • The request method is not GET/HEAD/POST
  • The content-type of the POST request is not Application/X-www-form-urlencoded, multipart/form-data or text/plain
  • The request sets a custom header field

As for the interface on the management side, I verify the permission of the interface. Each request needs to carry a user-defined field (token) in the header, so the browser sends an additional OPTIONS request to verify the security of the request.

Why is the OPTIONS request 500?

The OPTIONS request only carries the user-defined fields and does not carry the corresponding values. The token field is NULL during background verification, so the authentication fails and an exception is thrown.

How do I resolve this exception?

1. Add it to the Spring Boot project application.yml

spring:
mvc:
dispatch-options-request: true 
Copy the code

2. Add a filter

The first step: This class needs to implement the HandlerInterceptor class, HandlerInterceptor class is org. Springframework. Web. Servlet. HandlerInterceptor.

The specific code is as follows:

@Component public class RequestFilter implements HandlerInterceptor { public boolean preHandler(HttpServletRequest request,HttpServletResponse response,Object handler){ response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Allow-Credentials", "true"); response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS"); response.setHeader("Access-Control-Max-Age", "86400"); response.setHeader("Access-Control-Allow-Headers", "Authorization"); / / if the request is the OPTIONS the end of the if (HttpMethod. OPTIONS. The toString (). The equals (request) getMethod ())) { response.setStatus(HttpStatus.NO_CONTENT.value()); return false; } return true; }}Copy the code

Step 2: write a MyWebConfiguration such need WebMvcConfigurationSupport inheritance.

Specific code implementation:

@Component public class MyWebConfiguration extends WebMvcConfigurationSupport{ @Resource private RequestFilter requestFilter; @override public void addInterceptors(InterceptorRegistry registry) {// Cross-domain interceptor registry.addInterceptor(requestFilter).addPathPatterns("/**"); }}Copy the code

This elegantly solves the problem of Ajax cross-domain requests.