The original article address: segmentfault.com/a/119000001… This article mainly refers to the content of the original article, if you want to know more, please go to the original address.

Why cross-domains

Cross-domain is caused by the same origin policy of the browser, so 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.

When does cross-domain occur

Here are the situations where cross-domains can occur

/ / different / / http://www.test.com:8080 https://www.test.com:8080 domain name http://www.test.com:8080 http://www.tester.com:8080 // Same domain name, different port http://www.test.com:8080 http://www.test.com:8081 // Same main domain name, Subdomain different HTTP: / / http://www.a.test.com:8080 / / http://www.b.test.com:8080 domain name corresponding to the same IP and domain name http://www.test.com:8080 http://192.12.23.18:8080Copy the code

The following is the case where there is no cross-domain

/ / the same protocol + domain name + port between different file does not exist under the cross domain http://www.test.com:8080/a.js http://www.test.com:8080/b.jsCopy the code

Cross-domain is forbidden by the browser, not by the server. So the browser can send it to its own server, which then forwards it to the cross-domain server. Act as a layer of agency.

A, CORS

Previously, we used CORS, as a most common way to solve cross-domain. Access-control-allow-origin can be set at the back end if it is only a simple solution to cross-domain, but if the request requires cookies, it must be set at the front end.

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. Nginx reverse proxy sets proxy_cookie_domain and cookieDomainRewrite (NodeJs). 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

Front-end Settings:

Native ajax
var xhr = new XMLHttpRequest(); // Ie8/9 requires window.XDomainRequest compatibility // The front end is set to enable cookie xhr.withCredentials =true;

xhr.open('post'.'http://www.test.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
jQuery ajax
$.ajax({
    ...
   xhrFields: {
       withCredentials: true// front-end Settings with cookie}, crossDomain:true// Request headers contain additional cross-domain information, but cookies are not included... });Copy the code
Vue framework

Axios Settings:

axios.defaults.withCredentials = true
Copy the code

Vue – resource Settings:

Vue.http.options.credentials = true
Copy the code

The backend is set to JAVA

/ * * import packages: import javax.mail. Servlet. HTTP. HttpServletResponse; * Interface parameters defined in: HttpServletResponse Response */ // Allow cross-domain access domain name: write full port (protocol + domain name + port) if there is no port, do not add the end of the port'/'
response.setHeader("Access-Control-Allow-Origin"."http://www.test.com"); // Allow front-end authentication cookie: After this parameter is enabled, the domain name cannot beThe '*', you must specify a specific domain name, otherwise the browser will prompt response.setheader ("Access-Control-Allow-Credentials"."true"); Responsetheader (response.setheader ())"Access-Control-Allow-Headers"."Content-Type,X-Requested-With");
Copy the code
Second, the json

Using JSONP to handle cross-domains is actually the easiest way. JSONP inserts a Script tag into a document. Create a callback method through which data requests are received and processed. The server coordinates the callback method, passing in some parameters,

JSONP supports only GET requests

Create a script tag dynamically
<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.test.com/login?user=admin&callback=callBack'; document.head.appendCild(script); // Return the execution functionfunction callBack(res) {
        alert(JSON.stringify(res));
    }
</script>
Copy the code
Ajax
$.ajax({
    url: 'http://'.type: 'get',
    dataType: 'jsonp', 
    jsonpCallback: 'callBack',
    data: {},
    complete: function(res){
    }
})
Copy the code
Vue
this.$http.jsonp(url, {
    params: {},
    jsonp: 'callBack'
}).then((res) => {

})
Copy the code
Third, postMessage

PostMessage, as discussed in the previous article, is a new API in HTML5 that is very handy for handling multi-window cross-domain messaging. The main problems to be solved are:

  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

In short, it is a good way to solve cross-domain problems, which are mainly for page to page cross-domain messaging, rather than server interaction.

How to use postMessage depends on how useful it is

Four, nginx

As mentioned earlier, it is the same origin policy of the browser that causes the cross-domain problem, so we first access our local area when the data is requested, and then do a proxy forward when the interface is sent out. You can cross domains. With Nginx we can easily implement cross-domain. Cross-domain implementation with Nginx is mainly used in front-end development, or deployment using nginx to start services. Take a quick look at the nginx configuration

# proxy server
server {
    listen       80;
    server_name  www.test.com;

    location /apis { Add proxy configuration to access directory /apis
        proxy_pass   http://www.tester.com:8080;  # Reverse proxy
        proxy_cookie_domain www.tester.com www.domainA.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

Note that the/API indicates that proxy forwarding is only done when the directory is /apis. For others, keep the original request address. For details about how to install and use nginx, see nginx introduction and how to use it on MAC

Nodejs middleware proxy is cross-domain

The Nodejs middleware proxy uses http-proxy-middleware across domains. As anyone who has used it knows, this middleware can be used in different places to achieve the same effect.

  1. Start the service with Node, use in node startup,
var express = require('express');
var proxy = require('http-proxy-middleware');
var app = express();
app.use('/', proxy({// proxy cross-domain target interface target:'http://www.test.com:8080',
    changeOrigin: true,})); app.listen(3000);Copy the code
  1. Used in webpack configuration. Configure proxy in webpack-dev-server. Webpack-dev-server uses http-proxy-middleware to broker requests to an external server, as shown in the following example:
var webpack = require('webpack');
module.exports = {
    ....
    devServer: {
        port: '8088'// Set port number // proxy: {'/apis': {
                target: 'http://test.com:8080',
                secure: false}}}... };Copy the code
  1. Vue-cli proxyTable uses http-proxy-middleware webpack.config.js as part of the configuration:
proxyTable: {
   '/apis': {
    target: 'http://test.com:8080',
    changeOrigin: true,
    secure: false}},Copy the code

These three implementations are actually implemented using http-proxy-middleware middleware.

6. WebSocket protocol is cross-domain

WebSocket Protocol is a new protocol for HTML5. It realizes the full-duplex communication between browser and server, allows the server to push data to the client actively, and allows cross-domain communication. It is a good implementation of server push technology.

At present, we commonly use HTTP requests only when the client sends the request to the server, the server will give the corresponding reply. The server does not actively send messages to the client, so WebSocket solves this problem.

A common example is to use WebSocket for real-time data refresh.

// Create WebSocket connection.
const socket = new WebSocket('ws://localhost:8080');

// Connection opened
socket.addEventListener('open'.function (event) {
    socket.send('Hello Server! ');
});

// Listen for messages
socket.addEventListener('message'.function (event) {
    console.log('Message from server ', event.data);
});
</script>
Copy the code
Document.domain + iframe cross domain

This scenario is mainly the case where the primary domain is the same and the subdomain is different

http://www.test.com:8080
http://www.b.test.com:8080
Copy the code

Implementation principle: two pages through JS forced document.domain as the base of the primary domain, to achieve the same domain. Primary domain www.test.com:8080/index.html page

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

Subdomain www.b.test.com:8080/b.html page

<script>
    document.domain = 'domain.com'; // Get the parent window variable alert('parent user' + 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
<iframe id="iframe" src="http://www.test.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
  1. b.html
<iframe id="iframe" src="http://www.test.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
  1. c.html
<script> // Listen for b.HTML incominghashValue 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
Nine,window.name+ iframe across domains

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

var proxy = function(url, callback) {
    var state = 0;
    var iframe = document.createElement('iframe'); // Load the cross-domain page iframe.src = url; // The onload event is triggered twice, the first time the cross-domain page is loaded, and the data is saved in window.name iframe.onload =function() {
        if(state = = = 1) {/ / second onload after the success of the page (with domain proxy), read the same window. The domain name of the callback data (iframe. ContentWindow. Name); destoryFrame(); }else if(state = = = 0) {/ / first onload (cross-domain pages) after the success, switch to sympatric agent iframe page. The 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.test.com/proxy…. Intermediate proxy page, same domain as A.HTML, content is empty.

3.) B.HTML (www.test.com/b.html)

<script>
    window.name = 'This is domain2 data! ';
</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.

conclusion

Of all the ways to deal with cross-domain. The most common way to handle cross-domain is to use nginx or NodeJS proxies. If you are doing simple things, you can use JSONP, depending on your needs.