preface

In the front and back end interaction, it is common to encounter cross-domain requests. What is cross-domain and how to solve cross-domain, this article will discuss and share.

What is cross-domain

Because of the browser’s same-origin policy, non-same-origin cases can cause cross-domain problems. Cross-domain scenarios occur when the protocol, primary domain name, subdomain name, or port of the URL is different.

The cross-domain request was actually sent and the server responded, but the browser intercepted the return result.

Cross-domain solutions

(1) the json

How it works: Use the script tag to send requests to the server without cross-domain restrictions. It only supports the GET method.

Implementation process:

  • Encapsulate a method named jSONp that takes url, params, and callback and returns a promise.
  • Internal implementation, first create a function on the window with the same name as the callback function passed in, used to receive the data returned by the server, and after receiving, the dynamically created script is deleted, the window mounted on the method set to null
  • Create a script tag that concatenates the url, parameters, and callback functions passed into a script SRC
  • Finally, the server processes and returns a method that takes the name of the callback function passed in and passes the data to the client as arguments to the function.
Client-side implementation<! DOCTYPEhtml>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0" />
    <title>Document</title>
    <style></style>
  </head>
  <body>
    <button onclick="send()">Send the json</button>
    <script>
      function jsonp({ url, params, callback = 'show' }) {
        return new Promise((resolve, reject) = > {
          const script = document.createElement('script')
          // Create a callback function
          window[callback] = function (res) {
            resolve(res)
            document.body.removeChild(script)
            window[callback] = null
          }
          // Process parametersparams = { callback, ... params, }let arr = []
          for (const key in params) {
            arr.push(`${key}=${params[key]}`)
          }
          script.src = `${url}?${arr.join('&')}`
          document.body.appendChild(script)
        })
      }

      function send() {
        jsonp({
          url: 'http://localhost:2000/say'.params: {
            id: 1,
          },
        }).then((res) = > {
          console.log(res) // {id: 1, name: "sky"}})}</script>
  </body>
</html>

Copy the code

Server-side implementation

const express = require('express')

const app = express()

app.get('/say'.(req, res) = > {
  const { callback, id } = req.query
  if (id === '1') {
    let obj = { id: 1.name: 'sky' }
    res.end(`${callback}(The ${JSON.stringify(obj)}) `)}else if (id === '2') {
    let obj = { id: 2.name: 'jeeny' }
    res.end(`${callback}(The ${JSON.stringify(obj)}) `)}else {
    res.end(`${callback}(' This id does not exist ') ')
  }
})

app.listen(2000)

Copy the code

(2) CORS(Cross-source resource sharing)

The key to CORS implementation is the back end, which can be cross-domain as long as it is configured. To enable CORS, set access-Control-allow-Origin on the server. This attribute indicates which domain names can be accessed.

(3) the postMessage

It can solve the following two situations:

  • The page passes messages with nested iframes
Parent page 01.html<! DOCTYPEhtml>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0" />
    <title>Document</title>
  </head>
  <body>
    <h2>I am a 01. HTML</h2>
    <button onclick="handleMessage()">Send a message</button>
    <iframe
      src="http://localhost:5000/02.html"
      style="width: 300px; height: 300px"
    ></iframe>

    <script>
    // Iframe address cannot be in system file address format, can start a service
      function handleMessage() {
        const iframe = document.getElementsByTagName('iframe') [0]
        iframe.contentWindow.postMessage(
          'I am the content sent to page 02'.'http://localhost:5000/02.html')}window.addEventListener('message'.(res) = > {
        // Accept content from other pages
        console.log(res)
      })
    </script>
  </body>
</html>Child pages 02. HTML<! DOCTYPEhtml>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0" />
    <title>Document</title>
  </head>
  <body>
    <h2>I am a 02. HTML</h2>
    <button onclick="handleMessage()">Send a message</button>

    <script>
      function handleMessage() {
        window.parent.postMessage('Message back to page 01')}window.addEventListener('message'.(res) = > {
        // Accept content from other pages
        console.log(res)
      })
    </script>
  </body>
</html>

Copy the code
  • The page communicates with the page opened through window.open. Note: When the parent page sends a message to the child page, the child page must be opened by window.open, or an asynchronous message is set to be sent about 100ms later
The parent page 01. HTML<! DOCTYPEhtml>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0" />
    <title>Document</title>
  </head>
  <body>
    <h2>I am a 01. HTML</h2>
    <button onclick="handleMessage()">Send a message</button>

    <script>
      function handleMessage() {
        const iframe = window.open('http://localhost:5000/02.html')
        setTimeout(() = > {
          iframe.postMessage('I am the content sent to page 02')},100)}window.addEventListener('message'.(res) = > {
        // Accept content from other pages
        console.log(res)
      })
    </script>
  </body>
</html>Child pages 02. HTML<! DOCTYPEhtml>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0" />
    <title>Document</title>
  </head>
  <body>
    <h2>I am a 02. HTML</h2>
    <button onclick="handleMessage()">Send a message</button>

    <script>
      function handleMessage() {
        window.opener.postMessage('Message back to page 01')}window.addEventListener('message'.(res) = > {
        // Accept content from other pages
        console.log(res)
      })
    </script>
  </body>
</html>

Copy the code

(4) Through nginx reverse proxy

// Proxy server {listen 81; server_name www.domain1.com; location / { proxy_pass http://www.domain2.com:8080; # reverse proxy proxy_cookie_domain www.domain2.com www.domain1.com; # change cookie domain name index index.html index.htm; # When accessing Nignx with middleware proxy interface such as Webpack-dev-server, there is no browser participation, so there is no source restriction. Add_header access-Control-allow-origin http://www.domain1.com; * add_header access-control-allow-credentials true; * add_header access-control-allow-credentials true; }}Copy the code

(5) Through node middleware proxy

(6) Window. name + iframe applies only to iframe

(7) Using location.hash + iframe applies only to iframe

(8) Through document.domain + iframe

This method can only be used for secondary domain names with the same protocol and port, such as A.baidu.com and B.baidu.com. You only need to add document.domain =’baidu.com’ to the pages requiring communication.

The parent page 01. HTML<! DOCTYPEhtml>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0" />
    <title>Document</title>
  </head>
  <body>
    <h2>I am a 01. HTML</h2>
    <button onclick="handleMessage()">Access to content</button>
    <iframe
      src="http://localhost:5000/02.html"
      style="width: 300px; height: 300px"
    ></iframe>

    <script>
      document.domain = 'baidu.com'
      function handleMessage() {
        const iframe = document.getElementsByTagName('iframe') [0]
        iframe.contentWindow.a
      }
    </script>
  </body>
</html>Child pages.<script>
  document.domain = 'baidu.com'
  var a = 3
</script>
Copy the code