Simulation of cross-domain

When coordinating with the front end, a cross-domain problem will emerge from time to time, as follows:

Access to XMLHttpRequest at 'http://xxxx:xxx/hello' from origin 'http://vvvvv:vvvv' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Copy the code

What is cross-domain?

To ensure page security, the browser sets the same-origin policy. That is, the script in the local domain can only read and write resources in the local domain but cannot access resources in other domains. The same source indicates that the protocol, domain name, and port are the same. If you access resources from a site that are not from the same source, the browser will report a cross-domain error. Two same origin policies for browsers can cause cross-domain problems:

  • DOM same-origin policy. Do not operate on the DOM of different source pages, including iframe, Canvas, etc. If the iframe of different sources prohibits data interaction, the Canvas containing different source data will be polluted and cannot be operated.
  • XmlHttpRequest Same-origin policy. Simply disable AJAX requests from different sources, mainly to prevent CSRF attacks.

The same origin policy is a browser behavior, so don’t tell me that it worked by myself or that it worked with PostMan.

Simulate a cross-domain

Create two new SpringBoot projects: A and B. Port A 8080, port B 8081.

Project A builds A AController

@RestController
public class AController {
    @GetMapping("/hello")
    public String hello(a) {
        return "hello"; }}Copy the code

Project B creates static/index.html

<! DOCTYPEhtml>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
    <title>Hello</title>
</head>
<body>
<div id="show"></div>
<input type="button" onclick="btnClick()" value="get_button">
<script>
    function btnClick() {
        $.get('http://localhost:8080/hello'.function (msg) {$("#show").html(msg);
        });
    }
</script>
</body>
</html>
Copy the code

Then start the project after access localhost: 8081 / index. HTML, click on the button will trigger the cross-domain.

Cross-domain solutions

There are many solutions for cross-domain networking, but I’ll just mention some of the common ones. Cross-domain issues are not only a front end thing but also a back end thing. The traditional cross-domain solution is JSONP, but JSONP only supports GET requests. Our backend is currently using CORS to solve cross-domain.

What is the CORS

CORS is a W3C standard that stands for Cross-Origin Resource Sharing. It allows browsers to make XMLHttpRequest requests to cross-source servers, overcoming the limitation that AJAX can only be used from the same source.

CORS needs to be supported by both the browser and the server, that is, the browser and the server need to have the corresponding technical support to use CORS.

Principle of CORS

Browsers divide CORS requests into two categories: simple requests and non-simple requests. The request flow is different for the two different request browsers.

Tips: A simple request is made if the following two conditions are met:

  1. The request method is one of three

    • HEAD, GET, and POST
  2. HTTP header information should not exceed the following fields:

    • Accept, Accept-language, Content-language, last-event-ID, and Content-type: Only three values are allowedapplication/x-www-form-urlencoded,multipart/form-data,text/plain.

Simple request process:

  1. The browser realizes that the cross-source AJAX request is a simple request and automatically adds an Origin field to the Header: Origin: http://localhost:8081.

  2. The server receives the request and checks whether the server is in the whitelist. If it is, the Response Header will have several more:

    Access-Control-Allow-Origin: http://localhost:8081 # This is the core
    Access-Control-Allow-Credentials: true  # This field is optional. Its value is a Boolean value indicating whether cookies are allowed to be sent.
    Access-Control-Expose-Headers: FooBar # This field is optional. When a CORS request is made, the XMLHttpRequest object's getResponseHeader() method only gets six basic fields. If you want to get the other fields, you must specify them in the access-control-exposing Headers.
    Copy the code
  3. The browser determines whether or not it returns this Header.

Non-simple request flow :(for example, the request method is PUT or DELETE, or the content-type field Type is application/json.)

  1. Before formal communication, add an HTTP query request called a “preflight” request using the request methodOPTIONSheaderOrigin. You can see in the console that an interface has been requested twice.
  2. The browser first asks the server if the domain name of the current web page is on the server’s licensed list, as well as what HTTP verbs and header fields to use. Only when a positive response is received will the browser send an official messageXMLHttpRequestRequest, or an error will be reported.
  3. Similarly, when the server detects whitelist, it returnsAccess-Control-Allow-OriginWait for Header information. At this point the precheck calculation is complete.
  4. Precheck is performed only once during the preset precheck period, and subsequent requests are treated as simple requests. When the timeout will be sent again.

use

Both Spring and SpringBoot provide support for CORS. Here’s how SpringBoot does it:

  1. Using the @crossorigin (Origins = “http://localhost:8081”) annotation, you can annotate the Controller method to indicate that the interface is allowed to cross domains. You can also annotate the Class to indicate that all interfaces under the Controller support the cross-domain.

    • @GetMapping("/hello")
      @CrossOrigin(origins = "http://localhost:8081")
      public String hello(a) {
          return "hello";
      }
      Copy the code
  2. If you have to do it in a lot of places, you can do it globally using the WebMvcConfigurerAdapter.

    • @Configuration
      public class CorsConfig extends WebMvcConfigurerAdapter {
          @Override
          public void addCorsMappings(CorsRegistry registry) {
              registry.addMapping("/ * *") // Paths that can be cross-domain
                  .allowedOrigins("*") // Whitelist of domain names
                  .allowedMethods("*")/*"GET", "POST", "DELETE", "PUT"*/
                  .allowedHeaders("*") // Allow access to all request headers. You can customize any request header
                  .maxAge(3600); // This complex request is for precheck. Set how long precheck will expire}}Copy the code
    • For details on other configurations and instructions, please refer to the source code comments.

  3. You can also use a Filter, which I don’t use very often, so I won’t write it down.

This is not safe, there is a CSRF danger. In the actual operation, browsers will classify requests into simple requests, pre-requests, and requests with credentials, etc. The pre-requests will first send an options probe request and negotiate with the browser whether to accept the request. Cross-domain requests do not require credentials by default, but the server can be configured to require credentials from the client to effectively avoid CSRF attacks.

Reference: cross-domain resource sharing CORS, rounding | Spring CORS through cross-domain problem in the Boot