What is cross-domain?

Cross-domain refers to a document or script in one domain trying to request a resource in another domain. Cross-domain is defined broadly here.

In a broad sense, cross-domain:



1.) Resource jump: A link, redirect, form submission 2.<link>,<script>,<img>,<frame>3.) Script request: AJAX request initiated by JS, cross-domain operation of DOM and JS objects, etcCopy the code

In fact, what we usually mean by cross-domain is narrowly defined, a class of request scenarios that are restricted by the browser’s same-origin policy.

What is the same origin policy? The Same Origin Policy (SOP) is a convention introduced by Netscape into the browser in 1995. It is the core and most basic security function of the browser. Without the Same Origin policy, the browser is vulnerable to XSS and CSFR attacks. Same-origin means that the protocol, domain name, and port are the same. Even if two different domain names point to the same IP address, they are not same-origin.

The same origin policy restricts the following behaviors:



1.Cookie, LocalStorage, and IndexDB cannot be read2.DOM and Js objects are not available3.AJAX requests cannot be sentCopy the code

Common cross-domain scenarios



URL indicates whether communication is allowedhttp://www.domain.com/a.js
http://www.domain.com/b.js Same domain name, different files or paths allowed
http://www.domain.com/lab/c.js

http://www.domain.com:8000/a.js
http://www.domain.com/b.js The same domain name, different ports are not allowed
 
http://www.domain.com/a.js
https://www.domain.com/b.js Same domain name, different protocols do not allow
 
http://www.domain.com/a.js
http://192.168.4.12/b. Js domain names cannot correspond to the same IP address
 
http://www.domain.com/a.js
http://x.domain.com/b.js The primary domain is the same, but the subdomain is different
http://domain.com/c.js
 
http://www.domain1.com/a.js
http://www.domain2.com/b.js different domain names are not allowedCopy the code

Cross-domain solutions

Hash + iframe 4. Window. name + iframe 5. PostMessage 6. Cross-domain resource sharing (CORS) 7, Cross-domain nginx proxy 8, cross-domain NodeJS middleware proxy 9, cross-domain WebSocket protocol

First, cross domains through JSONP

Usually, in order to reduce the load of the Web server, we separate static resources such as JS, CSS and IMG to another server with an independent domain name, and then load static resources from different domain names in the HTML page through corresponding tags, which are allowed by the browser. Based on this principle, we can dynamically create script. Request a reference url to achieve cross-domain communication.

1.) Native implementation:



 <script>
    var script = document.createElement('script');
    script.type = 'text/javascript';

    // Pass the parameter and specify the callback execution function as onBack
    script.src = 'http://www.domain2.com:8080/login?user=admin&callback=onBack';
    document.head.appendChild(script);

    // The callback executes the function
    function onBack(res) {
        alert(JSON.stringify(res));
    }
 </script>Copy the code

The server returns the following (executes the global function when it returns) :



onBack({"status": true."user": "admin"})Copy the code

2. Jquery Ajax:



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

3.) the vue. Js:



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

Examples of back-end Node.js code:



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

server.on('request'.function(req, res) {
    var params = qs.parse(req.url.split('? ') [1]);
    var fn = params.callback;

    // jsonp returns Settings
    res.writeHead(200, { 'Content-Type': 'text/javascript' });
    res.write(fn + '(' + JSON.stringify(params) + ') ');

    res.end();
});

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

Disadvantages of JSONP: Only one get request can be implemented.

Document.domain + iframe cross domain

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

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.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.) B.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

Window. Name + iframe cross domain

The window.name attribute is unique in that the name value persists across different pages (and even different domain names) and supports very long name values (2MB).

1.) A.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

2.) proxy. HTML: (www.domain1.com/proxy… Intermediate proxy page, same domain as A.HTML, content is empty.

3.) B.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.

PostMessage is cross-domain

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: A.) data transfer between the page and the new window it opens b.) message transfer between multiple Windows c.) message transfer between the page and nested iframe d.) cross-domain data transfer for the three scenarios above

Usage: The postMessage(data, Origin) method takes two arguments data: the HTML5 specification supports any primitive type or replicable object, but some browsers only support strings, so it’s best to serialize the argument with json.stringify (). Origin: protocol + host + port number. The value can also be set to “*”, which indicates that it can be sent to any window. If you want to specify the origin of the current window, set it to “/”.

1.) A.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');
    iframe.onload = function() {
        var data = {
            name: 'aym'
        };
        // Send cross-domain data to domain2
        iframe.contentWindow.postMessage(JSON.stringify(data), 'http://www.domain2.com');
    };

    // Accept data from domain2
    window.addEventListener('message'.function(e) {
        alert('data from domain2 ---> ' + e.data);
    }, false);
</script>Copy the code

2.) B.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

Vi. Cross-domain Resource Sharing (CORS)

Common cross-domain request: Only access-Control-allow-origin is required on the server. Cookie request: Both the front and back ends need to set fields. In addition, note that the cookie carried is the cookie of the domain where the cross-domain request interface resides, not the current page. Currently, all browsers support this functionality (IE8+ : IE8/9 requires the use of XDomainRequest objects to support CORS), and CORS has become a mainstream cross-domain solution.

1. Front-end Settings:

1.) Native Ajax



// Set whether cookies are included in the front end
xhr.withCredentials = true;Copy the code

Sample code:



var xhr = new XMLHttpRequest(); // Ie8/9 must be window.xdomainRequest compatible

// Set whether cookies are included in the front end
xhr.withCredentials = true;

xhr.open('post'.'http://www.domain2.com:8080/login'.true);
xhr.setRequestHeader('Content-Type'.'application/x-www-form-urlencoded');
xhr.send('user=admin');

xhr.onreadystatechange = function() {
    if (xhr.readyState == 4 && xhr.status == 200) { alert(xhr.responseText); }};Copy the code

2.) the jQuery ajax



$.ajax({
    ...
   xhrFields: {
       withCredentials: true    // Set whether cookies are included in the front end
   },
   crossDomain: true.// The request header contains additional cross-domain information, but does not contain cookies. });Copy the code

3.) The VUE framework adds the following code to the Vue-Resource wrapped Ajax component:



Vue.http.options.credentials = trueCopy the code
2. Server Settings:

If the Settings are successful, the console of the front-end browser will not display cross-domain error messages; otherwise, the Settings are not successful.

1.) Java background:



/ * * import packages: import javax.mail. Servlet. HTTP. HttpServletResponse; * Defined in interface parameters: HttpServletResponse Response */
response.setHeader("Access-Control-Allow-Origin"."http://www.domain1.com");  // Write full (protocol + domain + port)
response.setHeader("Access-Control-Allow-Credentials"."true");Copy the code

2.) Nodejs



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

server.on('request'.function(req, res) {
    var postData = ' ';

    // Data block received
    req.addListener('data'.function(chunk) {
        postData += chunk;
    });

    // Data is received
    req.addListener('end'.function() {
        postData = qs.parse(postData);

        // Cross-domain background Settings
        res.writeHead(200, {
            'Access-Control-Allow-Credentials': 'true'.// The backend allows sending cookies
            'Access-Control-Allow-Origin': 'http://www.domain1.com'.// Allowed domain (protocol + domain name + port)
            'Set-Cookie': 'l=a123456; Path=/; Domain=www.domain2.com; HttpOnly'   // HttpOnly: The script cannot read cookies
        });

        res.write(JSON.stringify(postData));
        res.end();
    });
});

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

Nginx proxies cross domains

1, nginx configuration to resolve iconfont cross-domain

Browser cross-domain access js, CSS, and img conventional static resources are the same-origin policy permission, but iconfont font file (eot | otf | the vera.ttf | woff | SVG) exception, at this time in nginx server to add the following configuration static resources.



location / { add_header Access-Control-Allow-Origin *;
}Copy the code
2. Nginx reverse proxy interfaces cross domains

Cross-domain principle: The same Origin policy is a security policy of the browser, not a part of the HTTP protocol. The server invokes the HTTP interface only using THE HTTP protocol, and does not execute JS scripts. There is no need for the same origin policy, so there is no crossing problem.

Nginx configure a proxy server (domain name and domain1 the same, different port) as a jumper, reverse proxy access to domain2 interface, and can incidentally modify the cookie in the domain information, convenient for the current domain cookie writing, cross-domain login.

Nginx configuration:



# proxy server
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 the domain name in cookie
        index  index.html index.htm;

        # When accessing Nignx using middleware proxy interfaces such as Webpack-dev-server, there is no browser participation, so there is no source restriction, the following cross-domain configuration can not be enabled
        add_header Access-Control-Allow-Origin http://www.domain1.com;  # If the current end is cross-domain only without cookies, the value can be *
        add_header Access-Control-Allow-Credentials true; }}Copy the code

1.) Front-end code examples:



var xhr = new XMLHttpRequest();

// Front-end switch: whether the browser reads and writes cookies
xhr.withCredentials = true;

// Access the proxy server in nginx
xhr.open('get'.'http://www.domain1.com:81/?user=admin'.true);
xhr.send();Copy the code

2.) Nodejs



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

server.on('request'.function(req, res) {
    var params = qs.parse(req.url.substring(2));

    // Write cookies to the front desk
    res.writeHead(200, {
        'Set-Cookie': 'l=a123456; Path=/; Domain=www.domain2.com; HttpOnly'   // HttpOnly: the script cannot read
    });

    res.write(JSON.stringify(params));
    res.end();
});

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

Nodejs middleware proxy across domains

Node middleware to achieve cross-domain proxy, the principle is roughly the same as Nginx, are by starting a proxy server, data forwarding.

1. Cross-domain of non-VUE framework (twice cross-domain)

Build a proxy server with Node + Express + HTTP-proxy-middleware.

1.) Front-end code examples:



var xhr = new XMLHttpRequest();

// Front-end switch: whether the browser reads and writes cookies
xhr.withCredentials = true;

// Access the HTTP-proxy-Middleware proxy server
xhr.open('get'.'http://www.domain1.com:3000/login?user=admin'.true);
xhr.send();Copy the code

2.) Middleware server



var express = require('express');
var proxy = require('http-proxy-middleware');
var app = express();

app.use('/', proxy({
    // Proxy cross-domain target interface
    target: 'http://www.domain2.com:8080'.changeOrigin: true.// Modify the response header information to cross-domain and allow cookies
    onProxyRes: function(proxyRes, req, res) {
        res.header('Access-Control-Allow-Origin'.'http://www.domain1.com');
        res.header('Access-Control-Allow-Credentials'.'true');
    },

    // Change the cookie domain name in the response information
    cookieDomainRewrite: 'www.domain1.com'  // The value can be false, indicating no change
}));

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

3. Nginx: Nginx

2. Cross-domain of VUE framework (once cross-domain)

Cross domain using node + Webpack + webpack-dev-server agent interface. In the development environment, since the Vue rendering service and the interface proxy service are the same as Webpack-dev-server, there is no need to set headers cross-domain information between the page and proxy interface.

Webpack.config.js part configuration:



module.exports = {
    entry: {},
    module: {},... devServer: {historyApiFallback: true.proxy: [{
            context: '/login'.target: 'http://www.domain2.com:8080'.// Proxy cross-domain target interface
            changeOrigin: true.cookieDomainRewrite: 'www.domain1.com'  // The value can be false, indicating no change}].noInfo: true}}Copy the code

9. WebSocket protocol is cross-domain

WebSocket Protocol is a new protocol for HTML5. It implements full duplex communication between browser and server, and allows cross-domain communication. It is a good implementation of server push technology. The native WebSocket API is not very convenient to use. We use socket. IO, which encapsulates the WebSocket interface well, provides a simpler, flexible interface, and provides backward compatibility for browsers that do not support WebSocket.

1.) Front-end code:



<div>User input:<input type="text"></div>
<script src="./socket.io.js"></script>
<script>
var socket = io('http://www.domain2.com:8080');

// The connection was successfully processed
socket.on('connect'.function() {
    // Listen for server messages
    socket.on('message'.function(msg) {
        console.log('data from server: ---> ' + msg); 
    });

    // The listener server is closed
    socket.on('disconnect'.function() { 
        console.log('Server socket has closed.'); 
    });
});

document.getElementsByTagName('input') [0].onblur = function() {
    socket.send(this.value);
};
</script>Copy the code

Nodejs socket background:



var http = require('http');
var socket = require('socket.io');

// Start the HTTP service
var server = http.createServer(function(req, res) {
    res.writeHead(200, {
        'Content-type': 'text/html'
    });
    res.end();
});

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

// Listen for socket connections
socket.listen(server).on('connection'.function(client) {
    // Receive information
    client.on('message'.function(msg) {
        client.send('hello:' + msg);
        console.log('data from client: ---> ' + msg);
    });

    // Disconnect processing
    client.on('disconnect'.function() {
        console.log('Client socket has closed.'); 
    });
});Copy the code