preface
First of all, what is cross-domain? Simply understand that because of the restriction of JavaScript same-origin policy, JS under the domain name of a.com cannot operate the object under the domain name of b.com or c.a.com
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.
1, the json
JSONP is JSON with Padding or parametric JSON.
JSONP implements cross-domain requests simply by dynamically creating <script> tags and then using <script> SRC to retrieve data across domains without being constrained by the same origin policy.
JSONP consists of two parts: the callback function and the data callback function is the function that should be called in the page when the response arrives. The name of the callback function is usually specified in the request. The data is the JSON data passed into the callback function
Create the
var script = document.createElement("script");
script.src = "https://api.douban.com/v2/book/search?q=javascript&count=1&callback=handleResponse"
document.body.insertBefore(script, document.body.firstChild);
Copy the code
On the page, the returned JSON is passed as an argument to the callback function, which we use to manipulate the data.
functionHandleResponse (response){// Code to operate on response data}Copy the code
2, postMessage
PostMessage is an API introduced by HTML5. The postMessage() method allows scripts from different sources to communicate effectively in an asynchronous manner, enabling cross-text document, multi-window, and cross-domain messaging. It is mainly used for inter-window data communication, which makes it an effective solution for cross-domain communication.
Sending data:
otherWindow.postMessage(message, targetOrigin, [transfer]);
Copy the code
otherWindow
A reference to a window, such as the contentWindow property of iframe, the window object returned by executing window.open, or the named or numerically indexed window.frames.
message
Data to be sent to the other Windows, it will be structured clone algorithm [!] (https://developer.mozilla.org/en-US/docs/DOM/The_structured_clone_algorithm) serialization. This means you can safely pass data objects to the target window without having to serialize them yourself.
targetOrigin
The origin attribute of a window is used to specify which Windows can receive message events. Only the corresponding Windows under the origin attribute can receive messages after being specified. If the wildcard character is set to “*”, the message can be sent to any window, but this is not recommended for security reasons. If you want to send to a window of the same origin as the current window, set it to “/”.
Transfer | optional attribute
Transferable is a list of **Transferable** objects that are passed along with Message. Ownership of these objects is transferred to the receiver of the message, and no ownership is retained by the sender.
Receive data: Listens for message events
window.addEventListener("message", receiveMessage, false);function receiveMessage(event) {
var origin= event.origin;
console.log(event);
}Copy the code
The screenshot of the event object is as follows:
The four properties of the Event object
- Data: a message object sent from another window;
- Type: indicates the type of message to be sent.
- Source: the window object from which the message is sent;
- Origin: refers to the source of the window that sent the message
3. Cross-domain Resource Sharing (CORS)
CORS requires both browser and backend support. Internet Explorer 8 and 9 need to be implemented through XDomainRequest.
The browser will automatically carry out CORS communication, the key to achieve CORS communication is the back end. As long as the backend implements CORS, cross-domain is achieved.
To enable CORS, set access-Control-allow-Origin on the server. This attribute indicates which domain names can access resources. If a wildcard is set, all websites can access resources.
Although setting up CORS has nothing to do with the front end, solving cross-domain problems in this way can result in two cases of simple and complex requests being sent.
(1) Simple request
As long as the following two conditions are met, it is a simple request
Condition 1: Use one of the following methods:
- GET
- HEAD
- POST
Condition 2: The value of the content-Type is limited to one of the following:
- text/plain
- multipart/form-data
- application/x-www-form-urlencoded
None of the XMLHttpRequestUpload objects in the request have any event listeners registered; The XMLHttpRequestUpload object can be accessed using the xmlHttprequest.upload attribute.
(2) Non-simple request
A request that does not meet these criteria is definitely a complex request. The CORS request of complex request will add an HTTP query request, called “precheck” request, before formal communication. This request is the option method, through which to know whether the server allows cross-domain request.
When a PUT request is sent to the background, it is a complex request and the background needs to perform the following configuration:
// Which method is allowed to access me res.setheader ('Access-Control-Allow-Methods'.'PUT'// Precheck the survival time res.setheader ('Access-Control-Max-Age', 6) // OPTIONS request no processingif (req.method === 'OPTIONS') {res.end()} // Define what is returned in the background app.put('/getData'.function(req, res) {
console.log(req.headers)
res.end('I don't love you')})Copy the code
Let’s look at an example of a complete complex request and look at the CORS request-related fields
// index.html
let xhr = new XMLHttpRequest()
document.cookie = 'name=xiamen'// Cookies cannot cross domain xhr.withcredentials =true// Whether the front end is set with cookie xhr.open('PUT'.'http://localhost:4000/getData'.true)
xhr.setRequestHeader('name'.'xiamen')
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if((XHR. Status > = 200 && XHR. Status < 300) | | XHR. Status = = = 304) {the console. The log (XHR. Response) / / get the response headers, Access-control-expose-headers console.log(xhr.getresponseHeader ('name'))
}
}
}
xhr.send()Copy the code
//server1.js
let express = require('express');
let app = express();
app.use(express.static(__dirname));
app.listen(3000);
Copy the code
4. Node middleware proxy
In the process of front-end website development, the network request points to the interface provided by NodeJS, the NodeJS server then initiates the request to point to the cross-domain server, and then returns to the front-end page successively, so as to complete the cross-domain access, basically meeting the cross-domain access problem
The front-end code
var xhr = new XMLHttpRequest(); // Whether the browser reads and writes cookies xhr.withCredentials =true; // Access http-proxy-middleware proxy server xhr.open('get'.'http://www.127.0.0.1:3000/login?user=admin'.true);
xhr.send();Copy the code
express+ http-proxy-middleware
var express = require('express');
var proxy = require('http-proxy-middleware');
var app = express();
app.use('/', proxy({// proxy interface target:'http://www.127.0.0.1:8080',
changeOrigin: true// Modify the response header to cross-domain and allow cookie onProxyRes:function(proxyRes, req, res) {
res.header('Access-Control-Allow-Origin'.'http://www.127.0.0.1');
res.header('Access-Control-Allow-Credentials'.'true'); }, // Modify the cookie domain name in the response message cookieDomainRewrite:'www.127.0.0.1'/ / can befalse})); app.listen(3000);Copy the code
Koa+Koa2-cors
var Koa = require('koa');
var cors = require('koa2-cors');
var app = new Koa();
app.use(cors({
origin: function(ctx) {
if (ctx.url === '/') {
return false;
}
return The '*';
},
exposeHeaders: ['WWW-Authenticate'.'Server-Authorization'],
maxAge: 5,
credentials: true,
allowMethods: ['GET'.'POST'.'DELETE'],
allowHeaders: ['Content-Type'.'Authorization'.'Accept']})); app.listen(3000);Copy the code
5. 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.
The front end
The < div > user input: < inputtype="text"></div>
<script src="./socket.io.js"></script>
<script>
var socket = io('http://www.domain2.com:8080'); // Process socket.on('connect'.function() {// Listen for server message socket.on()'message'.function(msg) {
console.log('data from server: ---> '+ msg); }); // The listener closes the 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'); 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 to socket connections socket.listen(server).on('connection'.function(client) {// Receive the message 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
Window. Name + iframe
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).
Where A.HTML and B.HTML are sympatric, both are http://localhost:3000; And c. HTML is http://localhost:4000
// a.html(http://localhost:3000/b.html)
<iframe src="http://localhost:4000/c.html" frameborder="0" onload="load()" id="iframe"></iframe>
<script>
let first = true// The onload event fires twice, the first time the cross-domain page is loaded and the data is stored in window.namefunction load() {
if(first){// After the first onload(cross-domain page) succeeds, switch to the same-domain proxy pagelet iframe = document.getElementById('iframe');
iframe.src = 'http://localhost:3000/b.html';
first = false;
}else{/ / second onload (sympatric b.h HTML pages) after the success, read the same domain window. The name of the data to the console. The log (iframe. ContentWindow. Name); } } </script>Copy the code
B.html is an intermediate proxy page, in the same domain as A.HTML, with empty content.
// c.html(http://localhost:4000/c.html)
// c.html(http://localhost:4000/c.html)
<script>
window.name = 'I want to cross domains.'
</script>
Copy the code
The SRC attribute of iframe is used to transfer the cross-domain data from the outfield to the local region. In this case, the window.name of iframe is used to transfer the cross-domain data from the outfield to the local region. This is a neat way to circumvent the browser’s cross-domain access restrictions, but it’s also a secure operation.
Location. hash + iframe
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.
// a.html
<iframe id="iframe" src="http://www.domain2.com/b.html" style="display:none;"></iframe>
<script>
var iframe = document.getElementById('iframe'); / / to the b.h HTMLhashvaluesetTimeout(function() {
iframe.src = iframe.src + '#user=admin'; }, 1000); // callback methods open to homologous C.HTMLfunction onCallback(res) {
alert('data from c.html ---> ' + res);
}
</script>
Copy the code
// b.html<iframe id="iframe" src="http://www.domain1.com/c.html" style="display:none;"></iframe>
<script>
var iframe = document.getElementById('iframe'); // listen for a.htmlhashValue, which is passed to C.html window.onhashchange =function () {
iframe.src = iframe.src + location.hash;
};
</script>Copy the code
// c.html <scripthashValue window. Onhashchange =function() {/ / and by operating with domain a.h HTML js callback, the results back to the window. The parent, the parent. OnCallback ('hello: ' + location.hash.replace('#user='.' '));
};
</script>Copy the code
Document.domain + iframe
This mode can be used only when the secondary domain names are the same. For example, a.test.com and b.test.com are used in this mode. Just add document.domain =’test.com’ to the page to indicate that the secondary domain is the same.
Implementation principle: two pages through JS forced document.domain as the base of the primary domain, to achieve the same domain.
Let’s look at an example: page a.zf1.cn:3000/a.html gets the value of a in page b.zf1.cn:3000/b.html
// a.html
<body>
helloa
<iframe src="http://b.zf1.cn:3000/b.html" frameborder="0" onload="load()" id="frame"></iframe>
<script>
document.domain = 'zf1.cn'
function load() {
console.log(frame.contentWindow.a);
}
</script>
</body>Copy the code
// b.html
<body>
hellob
<script>
document.domain = 'zf1.cn'
var a = 100;
</script>
</body>
Copy the code
Nginx proxy cross domain
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
The front-end code
var xhr = new XMLHttpRequest(); // Front-end switch: whether the browser reads and writes cookies xhr.withCredentials =true; // Access the proxy server xhr.open('get'.'http://www.domain1.com:81/?user=admin'.true);
xhr.send();Copy the code
Nodejs background
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 cookie res.writeHead(200, {'Set-Cookie': 'l=a123456; Path=/; Domain=www.domain2.com; HttpOnly'// HttpOnly: script cannot read}); res.write(JSON.stringify(params)); res.end(); }); server.listen('8080');
console.log('Server is running at port 8080... ');Copy the code
conclusion
Nginx is recommended to solve cross-domain problems. It has the following advantages:
- Excellent compatibility, can be used in all browsers
- Low cost, no additional server configuration, no front-end code modifications
- Saves server performance
- It can carry sessions without additional authentication information such as cookies