The same origin policy restricts the following behaviors:

  • 1. Cookies, LocalStorage, and IndexDB cannot be read
  • 2.DOM and Js objects cannot be obtained
  • 3.AJAX requests cannot be sent
// Server code
const Koa = require('koa');
const app = new Koa();

app.use(async ctx => {
  ctx.body = 'Hello World';
});

app.listen(3000);
Copy the code
// Browser-side code
let xhr = new XMLHttpRequest()
xhr.open("GET"."http://localhost:3000/api")
xhr.onreadystatechange = function(response) {
    console.log(response)
}
xhr.send()
Copy the code

The same-origin policy

As defined in MDN, the same origin policy is an important security policy that restricts how an Origin document or the script it loads can interact with resources from another source. It can help block malicious documents and reduce the number of vectors that can be attacked. In layman’s terms, browsers cannot directly access source sites. The same domain name, protocol, and port are all the same.

The domain across up

Today I will summarize the cross-domain approach:

  • 1.jsonp
  • 2.cors
  • 3. The agent
  • 4.domain + iframe
  • 5. Location. hash + iframe cross-domain
  • 6. Window. name + iframe cross domains
  • 7. PostMessage across domains

1.jsonp

Jsonp is the ability to request resources across domains using Script tags.

  • The browser generates the script tag resource SRC to point to the target interface.
  • The server wraps the response data into a JS function and calls function to call the response data back out.
// Client code
let url = "http://localhost:3000/api";
function cb(res){
    console.log(res)    // Response data
}
function jsonp(url){
    let script = document.createElement("script");
    script.src = url;
    document.body.appendChild(script)
}
jsonp(url)
Copy the code
// Server code
app.use(async ctx => {
  ctx.body = `function fn(cb){ cb("Hello World") } fn(cb)`;
});
Copy the code

Since JSONP relies on the ability of tags to load resources in older browsers, there is no way to set the request headers, request methods… , so the project is completely using JSONP to achieve cross-domain impossible.

2.CORS (Cross-origin Resource Sharing)

After receiving this request, CORS will first determine whether Origin is within the range of permitted sources (determined by the server). If the verification is successful, The server adds the access-Control-allow-origin and access-Control-allow-credentials fields in the Response Header.

// Server code
const Koa = require('koa');
const app = new Koa();

app.use(async ctx => {
    ctx.body = 'Hello World'
    ctx.set("Access-Control-Allow-Origin"."http://localhost:8000")}); app.listen(3000);
Copy the code

3. The agent

Since cross-domain is affected by the same origin policy of the browser, the browser can request the service of the current domain to access the server interface through a proxy, and the problem is solved.

/ / the browser, the current domain name http://localhost:8000/api
let xhr = new XMLHttpRequest()
xhr.open("GET"."http://localhost:8000/api")
xhr.onreadystatechange = function(response) {
    console.log(response)
}
xhr.send()
Copy the code
// Front-end static resource services
const Koa = require('koa');
const fs = require("fs");
const path = require("path");
const http = require("http");
const app = new Koa();

app.use(async ctx => {
 let apiReg = /^\/api/;
  if( apiReg.test( ctx.request.url ) ){
    let text = await new Promise((resolve, reject) = > {
        http.get({
            hostname: 'localhost'.port: 3000.path: ctx.request.url,
          }, (res) => {
            let buf = [];
            res.on('data', (data)=> {
                buf.push(data)
            })
            res.on('end', () = > {let text = buf.toString();
                resolve(text)
            })
          });
    })
    ctx.body = text;
    
  }else{
    let html = fs.readFileSync( path.resolve(__dirname, "./index.html"), {encoding: 'utf8'} ) ctx.body = html; }}); app.listen(8000);
Copy the code

4.domain + iframe

This solution applies only to cross-domain scenarios where the primary domain is the same and the subdomains are different. Implementation principle: two pages through JS forced document.domain as the base of the primary domain, to achieve the same domain. 1. Parent window :(www.domain.com/a.html)

<iframe id="iframe" src="http://child.domain.com/b.html"></iframe>
<script>
    document.domain = 'domain.com';
    var user = 'admin';
</script>
Copy the code

2. Sub-window :(child.domain.com/b.html)

<script>
    document.domain = 'domain.com';
    // Get the variables in the parent window
    alert('get js data from parent ---> ' + window.parent.user);
</script>
Copy the code

5. Location. hash + iframe cross-domain

Implementation principle: A wants to communicate with B across domains, which is achieved through the middle page C. Three pages, different fields use iframe location.hash to transfer values, the same fields directly js access to communicate.

A domain: A.html -> B domain: B.html -> A domain: C.HTML, A and B different domain can only hash value one-way communication, B and C are also different domain can only one-way communication, but C and A are the same domain, so C can access all objects on A page through parent. Parent. 1. A.h HTML: (www.domain1.com/a.html) –

<iframe id="iframe" src="http://www.domain2.com/b.html" style="display:none;"></iframe>
<script>
    var iframe = document.getElementById('iframe');

    // Pass hash values to B.html
    setTimeout(function() {
        iframe.src = iframe.src + '#user=admin';
    }, 1000);
    
    // callback methods open to homologous C.HTML
    function onCallback(res) {
        alert('data from c.html ---> ' + res);
    }
</script>
Copy the code

2. The b.h HTML: (www.domain2.com/b.html) –

<iframe id="iframe" src="http://www.domain1.com/c.html" style="display:none;"></iframe>
<script>
    var iframe = document.getElementById('iframe');

    // listen for hash values from A.html and pass them to C.HTML
    window.onhashchange = function () {
        iframe.src = iframe.src + location.hash;
    };
</script>
Copy the code

3. C. HTML: (www.domain1.com/c.html) –

<script>
    // Listen for hash values from B.html
    window.onhashchange = function () {
        // Return the result by manipulating the javascript callback of the same domain A.html
        window.parent.parent.onCallback('hello: ' + location.hash.replace('#user='.' '));
    };
</script>
Copy the code

6. Window. name + iframe cross domains

The window.name property of ifreame is unique in that the name value persists across different pages (and even different domain names) and can support very long name values (2MB).

  1. A.h HTML: (www.domain1.com/a.html) –
var proxy = function(url, callback) {
    var state = 0;
    var iframe = document.createElement('iframe');

    // Load the cross-domain page
    iframe.src = url;

    // The onload event fires twice, the first time the cross-domain page is loaded and the data is stored in window.name
    iframe.onload = function() {
        if (state === 1) {
            // After the second onload(syndomain proxy page) succeeds, the data in syndomain window.name is read
            callback(iframe.contentWindow.name);
            destoryFrame();

        } else if (state === 0) {
            // After the first onload succeeds, switch to the same-domain proxy page
            iframe.contentWindow.location = 'http://www.domain1.com/proxy.html';
            state = 1; }};document.body.appendChild(iframe);

    // After the data is retrieved, the iframe is destroyed to free memory; This also ensures security (not accessed by other fields frame JS)
    function destoryFrame() {
        iframe.contentWindow.document.write(' ');
        iframe.contentWindow.close();
        document.body.removeChild(iframe); }};// Request cross-domain B page data
proxy('http://www.domain2.com/b.html'.function(data){
    alert(data);
});
Copy the code
  1. Proxy. HTML: www.domain1.com/proxy… Intermediate proxy page, same domain as A.HTML, content is empty.
  2. B.h HTML: (www.domain2.com/b.html) –
<script>
    window.name = 'This is domain2 data! ';
</script>
Copy the code

Summary: The SRC attribute of iframe is used to pass the data from the outfield to the local region. The cross-domain data is passed from the outfield to the local region by the window.name of iframe. This is a neat way to circumvent the browser’s cross-domain access restrictions, but it’s also a secure operation.

7.postMessage

PostMessage is an API in HTML5 XMLHttpRequest Level 2, and is one of the few window properties that can operate across domains. It can be used to solve the following problems:

  1. Data transfer between the page and the new window it opens
  2. Messaging between multiple Windows
  3. Page with nested IFrame message delivery
  4. Cross-domain data transfer for the three scenarios above
<iframe id="iframe" src="http://www.domain2.com/b.html" style="display:none;"></iframe>
<script>       
    var iframe = document.getElementById('iframe');
    iframe.onload = function() {
        var data = {
            name: 'aym'}; / / to send cross domain data domain2 iframe. ContentWindow. PostMessage (JSON. Stringify (data),'http://www.domain2.com'); }; // Accept domain2 returns data window.adDeventListener ('message'.function(e) {
        alert('data from domain2 ---> ' + e.data);
    }, false);
</script>
Copy the code

B.h HTML: (www.domain2.com/b.html) –

<script> 
    // Receive data from domain1
    window.addEventListener('message'.function(e) {
        alert('data from domain1 ---> ' + e.data);

        var data = JSON.parse(e.data);
        if (data) {
            data.number = 16;

            // Send it back to domain1
            window.parent.postMessage(JSON.stringify(data), 'http://www.domain1.com'); }},false);
</script>
Copy the code

reference

  • Common cross-domain solutions on the front end (all) – quiet de precipitation