Cross domain
Cross-domain CORS stands for “cross-origin Resource Sharing”, in which documents or scripts in one domain attempt to request resources in another domain. In contrast to cross-domain, the Same Origin Policy (SOP) means that the protocol, domain name, and port are the Same. Without the same origin policy, browsers are vulnerable to XSS, CSFR, and other attacks.
The cross-domain function must be supported by both the browser and the server. Currently, all browsers support this function. Internet Explorer cannot be lower than Internet Explorer 10.
The entire cross-domain communication process is automatically completed by the browser, without user participation. For developers, cross-domain communication is no different from same-origin AJAX communication; the code is exactly the same. As soon as the browser discovers that an AJAX request crosses domains, it automatically adds some additional headers, and sometimes an additional request, but the user doesn’t notice.
Therefore, the key to achieve cross-domain communication is the server, as long as the server achieves cross-domain communication, it can be cross-domain communication.
Implement several scenarios across domains
JSONP
JSONP takes advantage of the “vulnerability” of
Nodejs code
const http = require('http');
const querystring = require('querystring');
const server = http.createServer((req, res) = > {
const params = querystring.parse(req.url.split('? ') [1]);
const cb = params.callback;
res.writeHead(200, { 'Content-Type': 'text/javascript' });
res.write(cb + '(' + JSON.stringify(params) + ') ');
res.end();
});
server.listen(8888);
Copy the code
index.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>
<script>
function handleCb(res) {
console.log(res); // {param1: "123", param2: "456", callback: "handleCb"}
}
</script>
<script src="http://localhost:8888/test? param1=123¶m2=456&callback=handleCb"></script>
</body>
</html>
Copy the code
Document.domain + iframe cross domain
This solution only applies to cross-domain application scenarios where the primary domain is the same and the subdomain is different. In order to simulate this scenario locally, you need to use Nginx to do some configuration first:
#Configure hosts for the system (Mac)
$ cd /etc
$ sudo vim host
#Add the following configuration to hosts
127.0.0.1 www.domain.com
127.0.0.1 child.domain.com
Copy the code
#Modify nginx configuration, configuration well remember to reloadserver { listen 80; server_name www.domain.com; location / { root html; index index.html index.htm; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } server { listen 80; server_name child.domain.com; location / { root html; index index.html index.htm; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; }}Copy the code
If you use this software will be more convenient some SwitchHosts, download the address swh.app, in addition to managing some agents, such as Mac, network -> Advanced -> agent -> ignore these host and domain agent Settings. In addition, remember to restart the browser, preferably in traceless mode.
Create a child. HTML file and place it in the WWW directory of nginx
<! 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>
child.com
<script>
console.log(window.parent.user)
</script>
</body>
</html>
Copy the code
Create a parent HTML, in nginx WWW directory, and then go to www.domain.com/parent.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>
<script>
var user = 'admin';
</script>
<iframe src="http://child.domain.com/child.html"></iframe>
</body>
</html>
Copy the code
At this point, open the console and you will find that there is an error
Then we make a change to force the document.domain of both pages to be the same
// Add the following code to both HTML scripts to access the data
// If you do not force change the document.domain of both urls to www.domain.com child.domain.com
document.domain = 'domain.com';
Copy the code
Location. hash + iframe cross-domain
Site A and site B are cross-domain, site A and site C are in the same domain, the value of iframe location.hash is used to transfer values between the three pages, and js is directly used to communicate between the same domains.
Website A is embedded in website B, and website B is embedded in website C. Website C and website A are in the same domain, so you can use window.parent-parent to get the object of website A. In this way, web site A sends data to web site B by changing its hash value, and web site B sends data to web site C by changing its hash value, and web site C can send data to web site A, thus completing two-way data transmission between two cross-domain web sites.
Hosts configuration
127.0.0.1 www.domain1.com
127.0.0.1 www.domain2.com
Copy the code
Nginx. Conf configuration
. server_name www.domain1.com; . server_name www.domain2.com;Copy the code
A web site a.html www.domain1.com/a.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>
<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>
</body>
</html>
Copy the code
B Web site b.html www.domain2.com/b.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>
<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>
</body>
</html>
Copy the code
C. HTML www.domain1.com/c.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>
<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>
</body>
</html>
Copy the code
The effect is as follows:
Window. name + iframe cross domain
The window. name attribute is the name of a Window. The name value persists after loading different pages and even different domains, and can be up to 2MB in size.
The onlaod event of the iframe is executed. When the iframe is executed for the first time, the iframe is immediately reassigned to the proxy page of the same domain. After the proxy page is loaded, the onload event of iframe will be executed for the second time, because the iframe contains the proxy page of the same domain, so we can get window.name, get the data, and destroy the iframe.
Note: If the iframe is not codomain, its window.name is not available and an error is reported.
The configuration of hosts and nginx.conf is the same as in the previous section.
A web site a.html www.domain1.com/a.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>
<script>
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);
});
</script>
</body>
</html>
Copy the code
Our domain agents web proxy surface. HTML www.domain1.com/proxy.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>
</body>
</html>
Copy the code
B Web site b.html www.domain2.com/b.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>
<script>
window.name = 'This is domain2 data! ';
</script>
</body>
</html>
Copy the code
The effect is shown below:
Window. PostMessage across domains
The window.postMessage() method can safely implement cross-source communication. The window.postmessage () method provides a controlled mechanism to circumvent this limitation and is safe as long as it is used correctly.
In broad terms, a window can get a reference to another window (such as targetWindow = window.opener) and then distribute a MessageEvent message by calling the targetwindow.postMessage () method on the window. The window receiving the message is free to process this event as needed. Arguments passed to window.postMessage(), such as message, are exposed to the window receiving the message through the message event object.
The window.postmessage () method generally resolves the following problems across domains:
- Data transfer between the page and the new window it opens
- Messaging between multiple Windows
- Page with nested IFrame message delivery
- Cross-domain data transfer for the three scenarios above
The window.postmessage (data, origin) method takes two arguments:
- Data: The HTML5 specification supports any primitive type or copiable 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 “/”.
A web site a.html www.domain1.com/a.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>
<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>
</body>
</html>
Copy the code
B Web site b.html www.domain2.com/b.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>
<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>
</head>
<body>
domain2
</body>
</html>
Copy the code
Cross-domain Resource Sharing (CORS)
For common cross-domain requests, only access-Control-allow-origin is required on the server. This parameter is not required on the front end. If cookie is required, access-Control-allow-origin is required on both the front and back ends.
Note that 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 current page. If you want to write cookies to the current page, see the following section.
Front-end code a website a.html www.domain1.com/a.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>
<script>
const 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:8888'.false);
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); }};</script>
</body>
</html>
Copy the code
Back-end NodeJS code
const http = require('http');
const server = http.createServer();
const qs = require('querystring');
server.on('request'.function (req, res) {
let 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
// Allowed domains (protocol + domain name + port). If this parameter is set to *, the request fails with xhr.withCredentials = true
'Access-Control-Allow-Origin': 'http://www.domain1.com'./* * Set the cookie to domain2:8888 instead of domain1, because the backend can not write cookies across domains (nginx reverse proxy can do this), * but as long as domain2:8888 write cookie authentication once, The following cross-domain interfaces can obtain cookies from domain2:8888, so that all interfaces can cross-domain access */
'Set-Cookie': 'l=a123456; Path=/; Domain=www.domain2.com:8888; HttpOnly'.// HttpOnly prevents js from reading cookies
});
res.write(JSON.stringify(postData));
res.end();
});
});
server.listen(8888);
Copy the code
Agent cross-domain
Proxies use Nginx to proxy across domains, or nodeJS to proxy. The principle is the same. Nginx proxy is recommended, simple and efficient.
Nginx configuration resolves iconFONT across domains
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
Nginx reverse proxy interfaces cross domains
server { listen 81; server_name www.domain1.com; location / { proxy_pass http://www.domain2.com:8888; # reverse proxy proxy_cookie_domain www.domain2.com www.domain1.com; Alter cookie root HTML; index index.html index.htm; #When middleware proxy interfaces such as Webpack-dev-server are used to access Nignx, no browser is involved at this time, so there is no same-origin restriction, and the following cross-domain configuration is not enabledadd_header Access-Control-Allow-Origin http://www.domain1.com; * add_header access-control-allow-credentials true; * add_header access-control-allow-credentials true; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; }}Copy the code
Nodejs code
const http = require('http');
const server = http.createServer();
const qs = require('querystring');
server.on('request'.function (req, res) {
let 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, {
'Set-Cookie': 'l=a123456; Path=/; Domain=www.domain2.com; HttpOnly'.// HttpOnly prevents js from reading cookies
});
res.write(JSON.stringify(postData));
res.end();
});
});
server.listen(8888);
Copy the code
The front-end code
<! 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>
<script>
const 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.domain1.com:81'.false);
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); }};</script>
</body>
</html>
Copy the code
The 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.
Nodejs code
// NPM I ws-S installation
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
console.log('ws on 8080');
wss.on('connection'.function (ws) {
ws.on('message'.function (message) {
ws.send('server response: ' + message);
console.log('received: %s', message);
});
});
Copy the code
Front-end code a website a.html www.domain1.com/a.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>
<script>
var ws = new WebSocket('ws: / / 127.0.0.1:8080');
ws.addEventListener('open'.function (event) {
ws.send('Hello Server! ');
});
ws.onmessage = function (evt) {
console.log("Received Message: " + evt.data);
ws.close();
};
ws.onclose = function (evt) {
console.log("Connection closed.");
};
</script>
</body>
</html>
Copy the code