Due to the same origin policy, only scripts that meet the same origin can obtain resources. Although this helps to ensure network security, on the other hand, it also limits the use of resources. So how do you cross domains? Here are some ways to cross domains.

One, JSONP cross-domain

How script tags are imported into JS files is not affected by cross-domain. Furthermore, tags with the SRC attribute are not affected by the same origin policy.

Based on this feature, we load the resource using the SRC attribute of the script tag. The data is placed on the server pointed to by the SRC attribute in json format.

Since we can’t determine the loading state of the script’s SRC, we don’t know if the data has been fetched, so we define the handler beforehand. The server will add this function name to the beginning of the data, and when all of the data is loaded, it will call our defined function, and then pass in the arguments to the data returned by the back end.

Example code: github.com/mfaying/les… Url: mfaying. Making. IO/lesson # / cros…

index.html

<! DOCTYPEhtml>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <script>
    function callback(data) {
      alert(data.test);
    }
  </script>
  <script src="./jsonp.js"></script>
</body>
</html>
Copy the code

jsonp.js

callback({"test": 0});
Copy the code

Accessing the index. HTML popover will display 0

The downside of this scheme is that only one get request can be implemented.

Document. domain + iframe cross-domain

This solution applies only to scenarios where the primary domain is the same but the subdomains are different.

For example, the main web page of Baidu is www.baidu.com, and websites such as zhidao.baidu.com and news.baidu.com are subdomains under the main domain www.baidu.com.

Implementation principle: Both pages through js set document.domain as the basis of the primary domain, the realization of the same domain, can interoperate resources. Example code: github.com/mfaying/les… Url: mfaying. Making. IO/lesson # / cros…

index.html

<! DOCTYPEhtml>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <iframe src="https://mfaying.github.io/lesson/cross-origin/document-domain/child.html"></iframe>
  <script>
    document.domain = 'mfaying.github.io';
    var t = '0';
  </script>
</body>
</html>
Copy the code

child.html

<! DOCTYPEhtml>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <script>
    document.domain = 'mfaying.github.io';
    alert(window.parent.t);
  </script>
</body>
</html>
Copy the code

3. Location. hash + iframe cross-domain

If the SRC attribute of the iframe is changed on the parent page, the value of location.hash is changed. If the parent page changes the SRC attribute of the iframe, the value of location.hash is changed.

Example code: github.com/mfaying/les… Url: mfaying. Making. IO/lesson # / cros…

index.html

<! DOCTYPEhtml>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <iframe src="child.html#" style="display: none;"></iframe>
  <script>
    var oIf = document.getElementsByTagName('iframe') [0];
    document.addEventListener('click'.function () {
      oIf.src += '0';
    }, false);
  </script>
</body>
</html>
Copy the code

child.html

<! DOCTYPEhtml>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <script>
    window.onhashchange = function() {
      alert(window.location.hash.slice(1));
    }
  </script>
</body>
</html>
Copy the code

Click on the index.html page and the popover will display 0

Window. name + iframe cross-domain

How it works: the window.name property can still exist after different pages (or even different domain names) are loaded, and the name can be assigned a long value (2MB).

In the iframe under the same page, set the name attribute of the window, and then the iframe, pointing to the homologous page at this time window name attribute values, so as to realize the cross-domain access to data. Example code: github.com/mfaying/les… Url: mfaying. Making. IO/lesson # / cros…

./parent/index.html

<! DOCTYPEhtml>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <script>
    var oIf = document.createElement('iframe');
    oIf.src = 'https://mfaying.github.io/lesson/cross-origin/window-name/child.html';
    var state = 0;
    oIf.onload = function () {
      if (state === 0) {
        state = 1;
        oIf.src = 'https://mfaying.github.io/lesson/cross-origin/window-name/parent/proxy.html';
      } else {
        alert(JSON.parse(oIf.contentWindow.name).test); }}document.body.appendChild(oIf);
  </script>
</body>
</html>
Copy the code

./parent/proxy. HTML empty file, only do proxy page

Copy the code

./child.html

<! DOCTYPEhtml>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <script>
    window.name = '{"test": 0}'
  </script>
</body>
</html>
Copy the code

PostMessage cross-domain

PostMessage is an HTML5 initiative that allows for cross-document messaging.

Usage getMessageHTML. PostMessage (data, origin); Data: Any basic type or replicable object supported by the HTML5 specification, but some browsers only support strings, so it’s best to serialize with json.stringify () when passing arguments. Origin: protocol + host + port number. It can also be set to “*”, indicating that it can be passed to any window, or “/” if you want to specify the same origin as the current window.

GetMessageHTML is our reference to the page we want to receive information from, which can be the contentWindow property of the iframe, the return value of window.open, or the value we get from window.frames by name or by subscript.

Example code: github.com/mfaying/les… Url: mfaying. Making. IO/lesson # / cros…

index.html

<! DOCTYPEhtml>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
    <iframe id='ifr' src='./child.html' style="display: none;"></iframe>
    <button id='btn'>click</button>
    <script>
      var btn = document.getElementById('btn');
      btn.addEventListener('click'.function () {
        var ifr = document.getElementById('ifr');
        ifr.contentWindow.postMessage(0.The '*');
      }, false);
    </script>
</body>
</html>
Copy the code

child.html

<! DOCTYPEhtml>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
    <script>
      window.addEventListener('message'.function(event){
        alert(event.data);
      }, false);
    </script>
</body>
</html>
Copy the code

Click the button on the index.html page, and the popover displays 0.

6. Cross-domain Resource Sharing (CORS)

As long as you set access-control-allow-Origin on the server, you can implement cross-domain requests. If cookie requests are set, both the front and back ends need to be set. Due to the restriction of the same origin policy, the cookie read is the cookie of the domain where the cross-domain request interface resides, not the cookie of the current page.

CORS is the mainstream cross-domain solution.

Native Node.js implementation

Example code: github.com/mfaying/les… Url: mfaying. Making. IO/lesson # / cros… The server.js command starts the local server.

index.html

<! DOCTYPEhtml>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <script
    src="https://code.jquery.com/jquery-3.4.1.min.js"
    integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="
    crossorigin="anonymous"></script>
</head>
<body>
  <script>
    $.get('http://localhost:8080'.function (data) {
      alert(data);
    });
  </script>
</body>
</html>
Copy the code

server.js

var http = require('http');
var server = http.createServer();

server.on('request'.function(req, res) {
  res.writeHead(200, {
    'Access-Control-Allow-Credentials': 'true'.// The backend allows cookies to be sent
    'Access-Control-Allow-Origin': 'https://mfaying.github.io'.// Allow access to the domain (protocol + domain + port)
    'Set-Cookie': 'key=1; Path=/; Domain=mfaying.github.io; HttpOnly'   // HttpOnly: The script cannot read the cookie
  });

  res.write(JSON.stringify(req.method));
  res.end();
});

server.listen('8080');
console.log('Server is running at port 8080... ');
Copy the code

Koa combined with KOA2-CORS middleware implementation

Example code: github.com/mfaying/les… Url: mfaying. Making. IO/lesson # / cros… (Before accessing, run the node server.js command to start the local server.)

index.html

<! DOCTYPEhtml>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <script
    src="https://code.jquery.com/jquery-3.4.1.min.js"
    integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="
    crossorigin="anonymous"></script>
</head>
<body>
  <script>
    $.get('http://localhost:8080'.function (data) {
      alert(data);
    });
  </script>
</body>
</html>
Copy the code

server.js

var koa = require('koa');
var router = require('koa-router') ();const cors = require('koa2-cors');

var app = new koa();

app.use(cors({
  origin: function (ctx) {
    if (ctx.url === '/test') {
      return false;
    }
    return The '*';
  },
  exposeHeaders: ['WWW-Authenticate'.'Server-Authorization'].maxAge: 5.credentials: true.allowMethods: ['GET'.'POST'.'DELETE'].allowHeaders: ['Content-Type'.'Authorization'.'Accept'],
}))

router.get('/'.async function (ctx) {
  ctx.body = "0";
});

app
  .use(router.routes())
  .use(router.allowedMethods());

app.listen(3000);
console.log('server is listening in port 3000');
Copy the code

7. WebSocket protocol cross-domain

The WebSocket protocol is a new protocol for HTML5. The ability to achieve full-duplex communication between browser and server, while allowing cross-domain, is a good implementation of server-side push technology.

Example code: github.com/mfaying/les… Url: mfaying. Making. IO/lesson # / cros… The server.js command starts the local WebSocket server.

Front-end code:

<! DOCTYPEhtml>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <script>
    var ws = new WebSocket('ws://localhost:8080/'.'echo-protocol');
    // Set up the connection to trigger the event
    ws.onopen = function () {
      var data = { "test": 1 };
      ws.send(JSON.stringify(data));// Can send data to background
    };
 
    // The callback method for receiving the message
    ws.onmessage = function (event) {
      alert(JSON.parse(event.data).test);
    }
 
    // Event triggered by disconnection
    ws.onclose = function () {
      conosle.log('close');
    };
  </script>
</body>
</html>
Copy the code

server.js

var WebSocketServer = require('websocket').server;
var http = require('http');
 
var server = http.createServer(function(request, response) {
  response.writeHead(404);
  response.end();
});
server.listen(8080.function() {
  console.log('Server is listening on port 8080');
});
 
wsServer = new WebSocketServer({
    httpServer: server,
    autoAcceptConnections: false
});
 
function originIsAllowed(origin) {
  return true;
}
 
wsServer.on('request'.function(request) {
    if(! originIsAllowed(request.origin)) { request.reject();console.log('Connection from origin ' + request.origin + ' rejected.');
      return;
    }
    
    var connection = request.accept('echo-protocol', request.origin);
    console.log('Connection accepted.');
    connection.on('message'.function(message) {
      if (message.type === 'utf8') {
        const reqData = JSON.parse(message.utf8Data);
        reqData.test -= 1;
        connection.sendUTF(JSON.stringify(reqData)); }}); connection.on('close'.function() {
      console.log('close');
    });
});
Copy the code

Nginx agent cross-domain

Principle: The same-origin policy is a security policy of the browser and is not part of the HTTP protocol. The server side calls the HTTP interface only using the HTTP protocol, there is no spanning problem.

Implementation: Nginx is used to configure a proxy server (with the same domain name and different port as test1) to act as a board jumper. The reverse proxy is used to access interface Test2, and the test information in cookies can be modified to facilitate cookie writing in the current domain and cross-domain login.

Nginx configuration:

#proxy server {listen 81; server_name www.test1.com; location / { proxy_pass http://www.test2.com:8080; # reverse proxy proxy_cookie_test www.test2.com www.test1.com; # Modify cookie index. HTML index. HTM; add_header Access-Control-Allow-Origin http://www.test1.com; * add_header access-control-allow-credentials true; * add_header access-control-allow-credentials true; }}Copy the code