Regarding cross-domain issues in front-end and back-end development (access to xmlhttprequest....has been blocked by policy..)

The following information is found in cross domain solution,what is cross domain

1. Homologous strategy (the following introduction is from Baidu Encyclopedia)


A simple understanding is that the protocol, domain name, and port number of the two URLs are the same, and the two URLs are said to be of the same origin. Otherwise it is cross domain

2. What is Cross-Origin (CORS full name Cross-Origin Resource Sharing, which means Cross-Origin Resource Sharing)

Generalized cross-domain:
1.) Resource jump: A link, redirection, form submission.

2.) Resource embedding: links, images, scripts in the dom tag, and external links to files such as background:url(), @font-face() in the style

3.) Script requests: ajax requests initiated by js, cross-domain operations of dom and js objects, etc.

What we usually call cross-domain is a narrow sense, which is a type of request scenario restricted by the browser same-origin policy.
Mainly because the same-origin policy described above restricts the following behaviors:
1.) Cookie s, LocalStorage and IndexDB cannot be read
2.) DOM and Js objects are not available
3.) AJAX requests cannot be sent
So it can be understood that the same-origin policy is the culprit for cross-domain problems :)

3. Classification of requests (simple requests and complex requests)

1. Simple request
A simple request must meet the following three conditions at the same time:
1) The request method can only be: GET, POST, HEAD
2) The HTTP request header restricts these fields: Accept, Accept-Language, Content-Language, Content-Type, Last-Event-ID
3)Content-type can only take: application/x-www-form-urlencoded, multipart/form-data, text/plain
2. Complex requests
If the conditions for a simple request are not met, then it is a complex request.
For complex requests, a pre-check request will be sent for verification before the formal request is sent, and the formal request can only be made after the verification is passed.
E.g:
The browser now wants to send a complex request for put, so before the put request is sent, the browser first sends an options request.
options request header information (some specific header information will be hidden, and only displayed during normal access):

OPTIONS /cors HTTP/1.1
Origin: localhost:3000
Access-Control-Request-Method: PUT // Indicates what HTTP request method to use
Access-Control-Request-Headers: X-Custom-Header // Represents a custom field sent by the browser
Host: localhost:3000
Accept-Language: zh-CN,zh;q=0.9
Connection: keep-alive
User-Agent: Mozilla/5.0...

After the server receives the options request, after checking the Origin, Access-Control-Request-Method and Access-Control-Request-Headers fields, and confirming that cross-origin requests are allowed, it can respond
options response header

HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://localhost:3000 // means http://localhost:3000 can access data
Access-Control-Allow-Methods: GET, POST, PUT      
Access-Control-Allow-Headers: X-Custom-Header    
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain

When a formal HTTP request is issued after the options request is passed, if the options request fails, the server will not allow the access, thus throwing an error
After the options request is passed, the browser sends a request

PUT /cors HTTP/1.1
Origin: http://api.zhenai.com
Host: api.alice.com
X-Custom-Header: value
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...

options request cache
In the options request, we can cache the result by setting the parameter Access-Control-Max-Age of the response header
For example: Access-Control-Max-Age: 600 means to cache the options test result for ten minutes

The change of the url will cause the cache to be invalid, and the return value of the options request needs to be re-validated
Preflight doesn't care about post data
If the header changes, if the custom header is removed to make the request a simple request, the options request will not be sent. If other header s are added, the value of Access-Control-Allow-Headers will be re-validated.
Cookie changes, as long as the backend allows sending cookies, changes in cookie values ​​will not cause cache invalidation.

Four, cross-domain solutions (personally tried the first three)

1. Cross-domain through jsonp (note that this method is only valid for get requests)
1) Native JS implementation:

 <script>
    var script = document.createElement('script');
    script.type = 'text/javascript';    // Pass parameters and specify the callback execution function as onBack
    script.src = 'http://www.domain2.com:8080/login?user=admin&callback=onBack'; document.head.appendChild(script); // callback execution function
    function onBack(res) {
        alert(JSON.stringify(res));
    } </script>

2)jquery ajax:

$.ajax({   
 url: 'http://www.domain2.com:8080/login',   
 type: 'get',   
 dataType: 'jsonp',  // The request method is jsonp
 jsonpCallback: "onBack",    // Custom callback function name
 data: {}
});

3)vue.js:

this.$http.jsonp('http://www.domain2.com:8080/login', 
{    
params: {},    
jsonp: 'onBack'
}
).then((res) => {
console.log(res); 
})

2, nginx proxy cross-domain
1) nginx configuration solves iconfont cross-domain
Cross-domain access by browsers to js, ​​css, img and other conventional static resources is permitted by the same-origin policy, except for iconfont font files (eot|otf|ttf|woff|svg), at this time, the following configuration can be added to the static resource server of nginx .
location / {
add_header Access-Control-Allow-Origin *;
}
2. nginx reverse proxy interface cross-domain
Cross-domain principle: The same-origin policy is a browser's security policy, not part of the HTTP protocol. Invoking the HTTP interface on the server side only uses the HTTP protocol, does not execute JS scripts, and does not require the same-origin policy, so there is no crossover problem.
Implementation idea: Configure a proxy server (the domain name is the same as domain1, but the port is different) through nginx as a springboard, and the reverse proxy accesses the domain2 interface, and you can modify the domain information in the cookie by the way, which is convenient for writing the current domain cookie and realizes cross-domain login.
nginx specific configuration:

#proxy server
server {    
listen       xxxx;    
server_name  www.xxxx.com;
    location / {
     proxy_pass http://localhost:3001;

        #Specify the method that allows cross-domain, * represents all
        add_header Access-Control-Allow-Methods *;

        #Cache of preflight commands, if not cached, two requests will be sent each time
        add_header Access-Control-Max-Age 3600;
        #Requests with cookie s need to add this field and set it to true
        add_header Access-Control-Allow-Credentials true;

        #Indicates that this domain is allowed to make cross-domain calls (the domain name and port where the client sends the request) 
        #$http_origin dynamically obtains the domain requested by the requesting client. The reason for not using * is that requests with cookie s do not support *.
        add_header Access-Control-Allow-Origin $http_origin;

        #Fields representing request headers Dynamic acquisition
        add_header Access-Control-Allow-Headers 
        $http_access_control_request_headers;

        #OPTIONS preflight command, the request is sent only when the preflight command passes
        #Check if the type of request is a preflight command
        if ($request_method = OPTIONS){
            return 200;
        }

    }
}

3, jquery's ajax and java background
jquery

$.ajax({   
 url: 'http://www.domain2.com:8080/login',   
 type: 'get',   
 dataType: 'jsonp',  // The request method is jsonp
 jsonpCallback: "onBack",    // Custom callback function name
 data: {}
});

The java backend code adds the following code to the controller request

// Domain name that allows cross-domain access: if there is a port, it needs to be written in full (protocol + domain name + port), if there is no port, do not add '/' at the end
response.setHeader("Access-Control-Allow-Origin", "*");
//* Agent allows all methods
response.setHeader("Access-Control-Allow-Methods", "*");
// Access-Control-Max-Age for CORS related configuration cache
response.setHeader("Access-Control-Max-Age", "3600");
// Two common custom headers that need to be set in the backend when prompting OPTIONS preflight
response.setHeader("Access-Control-Allow-Headers", "*");
// Allow front-end authentication cookie s: After enabling this option, the above domain name cannot be '*', and a specific domain name must be specified, otherwise the browser will prompt
response.setHeader("Access-Control-Allow-Credentials", "true");

4. WebSocket protocol cross domain
WebSocket protocol is a new protocol in HTML5. It realizes full-duplex communication between the browser and the server, and allows cross-domain communication, which is a good implementation of the server push technology.
The native WebSocket API is inconvenient to use. We use Socket.io, which well encapsulates the webSocket interface, provides a simpler and more flexible interface, and provides backward compatibility for browsers that do not support webSocket.

<div>user input: <input type="text"></div>
<script src="./socket.io.js"></script>
<script>
	var socket = io('http://www.domain2.com:8080');// The connection is processed successfully socket.on('connect', function() { // Listen for server messages
    socket.on('message', function(msg) {        console.log('data from server: ---> ' + msg); 
    });    // The listening server is closed
    socket.on('disconnect', function() { 
        console.log('Server socket has closed.'); 
    });
});document.getElementsByTagName('input')[0].onblur = function() {
    socket.send(this.value);
};
</script>

5,vue proxyTable
In fact, in our mainstream MVVM framework, configurations also provide the ability to solve cross-domain problems. Continue with the example of vue2.x, we can achieve cross-domain ask by adding configuration items in config/index.js:

proxyTable: {
    '/apis': {
        // test environment
        target: 'http://www.zhenai.com/', // interface domain name
        changeOrigin: true,  //Is it cross-domain
        pathRewrite: {
            '^/apis': ''   //Need to rewrite rewrite,
        } 
    }             
}

6. The solution of springboot
1) Add the @CrossOrigin annotation to the target method

@GetMapping("/list")
@CrossOrigin
public List<String> list(){
    List<String> list = Arrays.asList("Java");
    return list;
}

2) Add a CORS filter

@Configuration
public class CorsConfig {
    
    @Bean
    public CorsFilter corsFilter(){
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", corsConfiguration);
        return new CorsFilter(source);
    }
    
}

3) The third: implement the WebMvcConfigurer interface and rewrite the addCorsMappings method
If you use spring security at the same time, you need to modify it in the security configuration file, otherwise it will not take effect

@Configuration
public class CorsConfiguration implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOriginPatterns("*")//Which domains are allowed to access
                .allowedMethods("GET","POST","PUT","DELETE","HEAD","OPTIONS")//Which methods are allowed to access
                .allowCredentials(true)//Whether to allow cookie s
                .maxAge(3600)//Set the validity period of the browser query
                .allowedHeaders("*");//
    }
}

}

In the case of spring security

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .mvcMatchers("/hello1").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                // Cross-domain configuration
                .and()
                .cors()
                .configurationSource(configurationSource());
    }

    CorsConfigurationSource configurationSource() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowedHeaders(Collections.singletonList("*"));
        corsConfiguration.setAllowedMethods(Collections.singletonList("*"));
        corsConfiguration.setAllowedOrigins(Collections.singletonList("*"));
        corsConfiguration.setMaxAge(3600L);

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", corsConfiguration);
        return source;
    }

Tags: Javascript Front-end servlet

Posted by Deany on Mon, 26 Sep 2022 21:46:56 +0530