preface
Front – and back-end data interactions often encounter cross-domain requests. What is cross-domain and how can cross-domain be resolved? Let’s explore them one by one.
I. What is cross-domain? What are the causes?
The reason for cross-domain is that browsers employ a number of security mechanisms for security, one of which is the same origin policy. What is the same-Origin policy? To put it simply, the same origin policy is to ensure the security of user information, prevent malicious websites from stealing data, and prohibit the JS interaction between different domains. A difference in domain name, protocol, or port will trigger the same origin policy for the browser.
What are the limitations of the same origin policy?
- Cookie, LocalStorage, IndexedDB and other stored content
- DOM node
- After the AJAX request is sent, the result is intercepted by the browser
But browsers have three tags that allow us to support cross-domain
<img />
<script />
<link />
2. Cross-domain solution
1.jsonp
1. The principle of the json
Web pages can get JSON data dynamically generated from other sources, taking advantage of the fact that <script> tags have no cross-domain restrictions. JSONP requests must be connected to the server of the other party.Copy the code
-
Declare a callback function with a function name (sayHello) as a parameter value to be passed to the server that requests data across domains and a function parameter to fetch the target data (the data returned by the server).
-
Create a script tag, assign the address of the cross-domain API data interface to the SRC of the script, and pass the function name to the server at that address. The callback = sayHello).
-
When the server receives the request, it needs to do something special: concatenate the function name and the data it needs to give you into a string, for example: the function name is sayHello, and the data it prepares is sayHello(‘ Did you eat? ‘).
-
Finally, the server returns the data to the client through HTTP protocol. The client then calls the previously declared callback function (sayHello) to operate on the returned data.
2. The advantages and disadvantages the json
JSONP has the advantage of simple compatibility and can be used to solve the problem of cross-domain data access in mainstream browsers. The disadvantage is that only support for get methods is limited and insecure and may be subject to XSS attacks.
// index.html <! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, "> <title>jsonp</title> </head> <body> <script> function jsonp({url, params, cb }) { return new Promise((resolve, reject) => { let script = document.createElement('script'); window[cb] = function (data) { resolve(data); document.body.removeChild(script); } params = { ... params, cb }; // convert params to wd=b&cb=sayHello let arrs = []; for (let key in params) { arrs.push(`${key}=${params[key]}`); } script.src = `${url}? ${arrs.join('&')}`; document.body.appendChild(script); })} // Jsonp can only send get requests, does not support post put delete methods, insecure, XSS attacks jsonp({url: 'http://localhost:8888/hello', params: {wd: 'hello'}, cb: 'sayHello' }).then(res => { console.log(res) }) </script> </body> </html>Copy the code
// server.js let express = require('express'); let app = express(); app.get('/hello',function (req,res) { let {wd,cb} = req.query; console.log(wd); Res.end (' ${cb}(' have dinner ') ')}) app.listen(8888);Copy the code
2.cors
The principle of
CORS is the fundamental solution to cross-source AJAX requests. JSONP can only make GET requests, but CORS allows any type of request.
The entire CORS communication process is done automatically by the browser without user involvement. For developers, CORS communication is no different from same-origin AJAX communication, and the code is exactly the same. As soon as the browser discovers that an AJAX request crosses sources, it automatically adds some additional headers, and sometimes an additional request, but the user doesn’t notice. Therefore, the key to CORS communication is the server. As long as the server implements the CORS interface, cross-source communication is possible.
// index.html <! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, <meta HTTP-equiv =" x-UA-compatible "content=" IE =edge"> <title>Document</title> </head> <body> <script> let xhr = new XMLHttpRequest; document.cookie = 'name=xht'; xhr.withCredentials = true; xhr.open('PUT','http://localhost:4000/getData',true); xhr.setRequestHeader('name','zfpx'); xhr.onreadystatechange = function () { if(xhr.readyState === 4){ if(xhr.status>=200 && xhr.status < 300 || xhr.status ===304){ console.log(xhr.response); console.log(xhr.getResponseHeader('name')); } } } xhr.send(); </script> </body> </html>Copy the code
// server1.js
let express = require('express');
let app = express();
app.use(express.static(__dirname));
app.listen(3000);
Copy the code
// server2.js let express = require('express'); let app = express(); let whitList = ['http://localhost:3000'] app.use(function (req,res,next) { let origin = req.headers.origin; If (whitlist. includes(origin)){res.setheader (' access-Control-allow-origin ', origin); Res. setHeader(' access-Control-allow-headers ','name'); Res. setHeader(' access-control-allow-methods ','PUT'); SetHeader (' access-Control-allow-credentials ', true); Res.setheader (' access-Control-max-age ',6); res.setheader (' access-Control-max-age ',6); Res. setHeader(' access-Control-expose-headers ', 'name'); if(req.method === 'OPTIONS'){ res.end(); }} next(); }); app.put('/getData', function (req, res) { console.log(req.headers); res.setHeader('name','jw'); Res.end (" I don't love you ")}) app.get('/getData',function (req,res) {console.log(req.headers); Res.end (" I don't love you ")}) app.use(express.static(__dirname)); app.listen(4000);Copy the code
3.postMessage
The postMessage() method allows scripts from different sources to communicate asynchronously in a limited manner, enabling cross-text file, multi-window, cross-domain messaging. There are several situations in which it can address data transfer
- 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
Let’s look at an example: http://localhost:3000/a.html page to http://localhost:4000/b.html “I love you”, then the latter back. “I do not love you.”
// a.html <! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, <meta HTTP-equiv =" x-UA-compatible "content=" IE =edge"> <title>Document</title> </head> <body> A.html <iframe src="http://localhost:4000/b.html" frameborder="0" id="frame" onload="load()"></iframe> <script> function load() { let frame = document.getElementById('frame'); Frame. The contentWindow. PostMessage (' I love you ', 'http://localhost:4000'); Window. onmessage = function (e) {console.log(e.data,'b '); } } </script> </body> </html>Copy the code
// b.html <! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, <meta HTTP-equiv =" x-UA-compatible "content=" IE =edge"> <title>Document</title> </head> <body> <script> window.onmessage = function (e) {console.log(e.data,'a '); E.ource. PostMessage (' I don't love you ', e.olin)} </script> </body> </ HTML >Copy the code
4.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 // onload Name function load() {if(first){// after the first onload(cross-domain page) succeeds, Let iframe = document.getelementById ('iframe'); let 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) < script > window. The name = 'I do not love you < / 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.
5.document.domain + iframe
This mode can be used only when the secondary domain names are the same. For example, a.xht.com and B.xht.com are used in this mode. Just add document.domain =’xht.com’ to the page to indicate that the secondary domain is the same to achieve cross-domain. 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.xht.com:3000/a.html to get the value of a in page b.xht.com:3000/b.html
// a.html
<body>
helloa
<iframe src="http://b.xht.com:3000/b.html" frameborder="0" onload="load()" id="frame"></iframe>
<script>
document.domain = 'xht.com'
function load() {
console.log(frame.contentWindow.a);
}
</script>
</body>
Copy the code
// b.html
<body>
hellob
<script>
document.domain = 'xht.com'
var a = 100;
</script>
</body>
Copy the code
6.websocket
Websocket is a persistent protocol of HTML5, which realizes the full duplex communication between browser and server, and is also a cross-domain solution. WebSocket and HTTP are both application layer protocols based on TCP. However, WebSocket is a two-way communication protocol. After the connection is established, both the WebSocket server and client can actively send or receive data to each other. At the same time, the WebSocket needs to use HTTP protocol to establish a connection. After the connection is established, the two-way communication between the client and server is independent of HTTP.
Let’s start with an example: the local file socket. HTML sends and receives data to localhost:3000
// socket.html <script> let socket = new WebSocket('ws://localhost:3000'); Socket. onopen = function () {socket.send(' I love you '); } socket.onMessage = function (e) {console.log(e.data); } </script>Copy the code
// server.js let express = require('express'); let app = express(); let WebSocket = require('ws'); WSS = new websocket. Server({port:3000}); wss.on('connection',function(ws) { ws.on('message', function (data) { console.log(data); Ws. Send (' I don't love you ')}); })Copy the code
7.location.hash + iframe
Implementation principle: A passes a hash value to C, c passes the hash value to B, and B puts the result into a’s hash value. A.html and B.html are in the same domain, both http://localhost:3000. And c. HTML is http://localhost:4000
// a.html <iframe src="http://localhost:4000/c.html#iloveyou"></iframe> <script> window.onhashchange = function () { // Check hash changes console.log(location.hash); } </script>Copy the code
/ / b.h HTML < script > window. The parent, the parent. The location. The hash = location. The hash / / b.h HTML will result in a.h hash value of the TML, A.html can be accessed via parent. ParentCopy the code
// c.html
console.log(location.hash);
let iframe = document.createElement('iframe');
iframe.src = 'http://localhost:3000/b.html#idontloveyou';
document.body.appendChild(iframe);
Copy the code
8.nginx
The implementation principle is similar to Node middleware proxy, requiring you to build a nginx server for forwarding requests.
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.
3. Summary
-
CORS supports all types of HTTP requests and is the fundamental solution for cross-domain HTTP requests
-
JSONP supports only GET requests. The advantage of JSONP is that it supports older browsers and can request data from sites that do not support CORS.
-
Both the Node middleware proxy and the Nginx reverse proxy have no restrictions on the server through the same origin policy.
-
In daily work, the cross-domain solutions used more are CORS and NGINX reverse proxies