preface

In the spirit of learning and summarizing the attitude of writing the technical output, there are any mistakes and problems, please point out. For more technical output, check out my Github blog.

Sorted out some front-end learning resources, hoping to help people in need, address: learning resources summary.

Cross domain

Cross-domain means that resources with different protocols, host names, and port numbers attempt to communicate with each other. However, due to the restriction of the same origin policy of the browser, the inter-domain communication fails.

The most common actual scenario is that resources in other domains of the third party will be requested during project development. For example, when map API is used, the white list needs to be set when the key is set so that map API can be used normally.

When AJAX is used to request data resources of a third party in different domains, HTTP requests cannot be successfully sent if cross-domain problems are not handled, and the browser will issue an error warning.

The same-origin policy

MDN explains: The same origin policy restricts how documents or scripts loaded from the same source can interact with resources from another source. This is an important security mechanism for isolating potentially malicious files.

The purpose of the same origin policy of the browser is to prevent malicious attacks such as XSS and CSRF.

There are three interaction modes for the same origin policy:

  • Cross-domain writes are generally allowed, such as linking, redirecting, and so on.
  • It is generally possible to nest resources across domains, such as IMG, script tags, and so on.
  • Cross-domain read operations are generally not allowed.

Cross-domain scenario

Only the protocols, domain names and port numbers of resources are the same source.

The following is a cross-domain description of homology and between different sources.

URL instructions Whether to allow communication
www.demo.com/a.html

www.demo.com/b.html

www.demo.com/c.html
The same domain name allow
www.demo.com/news/a.html

www.demo.com/center/b.ht…

www.demo.com/server/c.ht…
Different folders under the same domain name allow
www.demo.com/a.html

www.demo.com:80/b.html
Different port numbers Don’t allow
www.demo.com/a.html

www.demo.com/b.html
Different protocols Don’t allow
www.demo.com/a.html

www.test.com/b.html
Different domain name Don’t allow
www.demo.com/a.html

test.demo.com/b.html
The primary domain is the same, but the subdomain is different Don’t allow

Cross-domain solutions

1. JSONP

Because the browser’s same-origin policy allows cross-domain resources such as script tags to be nested, resources of script tags are not restricted by the same-origin policy.

JSONP’s solution is to make cross-domain requests through script tags.

  • The front end sets up the callback function as a parameter to carry with the request URL.
  • After receiving the request, the back end returns the name of the callback function and the required data.
  • After the back end responds and returns data, the returned data is passed into the callback function and executed.
<! -- using script tags natively --><script>
    function jsonpCallback(data) {
        alert('Got the data. Open the console.');
        console.log(data);
    }
</script>
<script src="Http://127.0.0.1:3000? callback=jsonpCallback"></script>
Copy the code

You can also use AJAX GET requests to make cross-domain requests (axiOS GET cross-domain requests are the same).

<! -- AJAX GET request --><script>
    function jsonpCallback(data) {
        alert('Got the data. Open the console.');
        console.log(data);
    }
    $.ajax({
        type: 'GET'.// It must be a GET request
        url: 'http://127.0.0.1:3000'.dataType: 'jsonp'.// Set it to jSONp type
        jsonpCallback: 'jsonpCallback' // Set the callback function
    })
</script>
Copy the code

The advantages and disadvantages:

  • Compatibility is good, and earlier versions of IE also support this approach.

  • Only HTTP requests in GET mode are supported.

  • Only HTTP requests such as data communication between the front and back ends cannot solve the problem of data interaction and communication between pages in different domains.

2. CORS

CORS cross-domain resource sharing allows cross-domain communication after related Settings are performed on the server.

If the CORS cross-domain field is not set on the server, the server rejects the request and prompts an error warning.

The access-Control-allow-Origin field is set on the server. The value can be a domain name or an ‘*’ wildcard. After the field is set, the cross-domain request is allowed.

<script> $. Ajax ({type: 'post', url: 'http://127.0.0.1:3000', success: function(res) {alert(' get data, open console '); console.log(res); } }) </script>Copy the code

How do servers set cross-domain fields? The backend language Settings are inconsistent across domains. For details, refer to the API of the backend language.

Set the Node end

res.writeHead(200, {
    'Access-Control-Allow-Origin': The '*'
});

// Or use a framework like Express
res.header("Access-Control-Allow-Origin"."*");
Copy the code

For details on CORS, refer to this note, CORS cross-domain resource sharing.

3. Server Proxy

The way of proxy request through the server is also a solution to the browser cross domain problem. The same origin policy is a security policy for browsers, and the server is not restricted by the same origin policy. Therefore, cross-domain problems do not exist. The specific steps are as follows:

  • The front-end normally requests the interface provided by the server. For example, request interface: http://localhost:3000.
  • Through the server set up the proxy to send requests, requests to the data and then the required data back to the front end. For example, set the proxy request interface to cnodejs.org/api/v1/topi… The server agent requests the data back and returns the data http://localhost:3000 interface to the front end.
// The server proxy requests the code
// The server simply proxies the interface data through a normal HTTP request
// You can also use the proxy module to proxy, as for how to use the proxy module, to be studied and perfected
var url = 'https://cnodejs.org/api/v1/topics';        
https.get(url, (resp) => {
    let data = "";
    resp.on('data', chunk => {
        data += chunk;
    });
    resp.on('end', () => {
        res.writeHead(200, {
            'Access-Control-Allow-Origin': The '*'.'Content-Type': 'application/json; charset=utf-8'
        });
        res.end(data);
    });
})
Copy the code

4. location.hash + iframe

The implementation of location.hash + iframe cross-domain communication looks like this:

  • Pages A in different domains communicate with pages B, embed the IFrame in page A into page B, and add a hash value to the SRC of the IFrame.
  • After page B receives the hash value, it determines that page A is trying to communicate with itself and then passes the data to the hash value of page A by modifying the value of parent. Location.
  • However, since child pages are not allowed to directly modify the parent page’s hash value under IE and Chrmoe, a proxy page is required to pass data through c page, which is in the same domain as PAGE A.
  • Similarly, embed the IFrame into the C page in the B page, and the data to be transmitted will be transmitted to the C page through the hash value of the SRC link of the IFrame. Since page A and page C are in the same domain, You can modify the hash value of page A on page C or invoke the global function on page A.

The general process is:

A Page code

<script> var iframe = document.createElement('iframe'); iframe.style.display = 'none'; iframe.src = "http://localhost:8081/b.html#data"; document.body.appendChild(iframe); function checkHash() { try { var data = location.hash ? location.hash.substring(1) : ''; Console. log(' Obtained data is: ', data); }catch(e) {}} window.addEventListener('hashchange', function(e) {console.log(' listen for hash changes: ', location.hash.substring(1)); }) </script>Copy the code

B Page code

<script>
     switch(location.hash) {
         case '#data':
         callback();
         break;
     }
    function callback() {
        var data = "testHash"
        try {
            parent.location.hash = data;
        }catch(e) {
            var ifrproxy = document.createElement('iframe');
            ifrproxy.style.display = 'none';
            ifrproxy.src = 'http://localhost:8080/c.html#' + data;
            document.body.appendChild(ifrproxy);
        }
    }
 </script>  
Copy the code

C page code

<script>
    // Change the hash value of page A
    parent.parent.location.hash = self.location.hash.substring(1);
    // Call the global function of page A
    parent.parent.checkHash();
</script>
Copy the code

The advantages and disadvantages:

  • There is a limited amount of data that hash passes.
  • The data is directly exposed in the URL.

5. document.domain + iframe

This solution is limited to cross-domain resource solutions with the same primary domain and different sub-domains.

Actual application scenarios:

The previous project development, often encountered such cross-domain problems, roughly similar to the development of new products in the product page, before the official launch, are generally uploaded to the internal test environment, such as the domain name of the test environment is test.admin.com/xxx/xxx, and the project… For example, consumer-test.admin.com/xxx/xxx, the product page is deployed online separately and nested into the project via iframe. During internal testing, the product page test environment and the project test environment have the same primary domain but different sub-domains, and the global public resources defined in the project need to be used in the product page. Due to cross-domain problems, these public resources cannot be obtained.

The cross-domain solution to this scenario is to utilize document.domain Settings. Cross-domain can be achieved by setting document.domain to the same domain in the product page and project, and the nested product page can access the common resources of the parent page. One thing to note is that document.domain Settings are limited to their own or higher parent fields, and the primary fields must be the same.

Project page

<iframe src="test.admin.com/xxx/xxx"></iframe>
<script>
    document.domain = 'admin.com';
</script>
Copy the code

Product page

<script>
    // Public resources defined in the project page are available
    document.domain = 'admin.com';
</script>
Copy the code

6. window.name + iframe

Window.name refers to the name of the current browser window. By default, it is an empty string. Each window’s window.name is independent. The nested iframe page also has its own window object, which is a child of top Window and also has the window.name attribute.

The unique thing about window.name is that when you set the value of window.name on a page, you set the name of the window, and then load other pages (even pages of different domains) in that window, the value of window.name remains (if it is not reset, the value will not change). And the window.name value supports large storage (2MB).

For example, open the console on a random page and set the name of the current window.

window.name = 'test-name';
Copy the code

After setting, you can jump to other pages in this window

window.location = 'https://www.baidu.com';
Copy the code

The page jumps to baidu home page, but the value of window.name is still the same as the value set before, because the page is jumped in a window, and the window name will not be changed.

The cross-domain solution is as follows.

http://localhost:8080/a.html and http://localhost:8081/b.html cross-domain communication, a page by nested iframe page b, b in the page setup window. The value of the name, is due to different domains, Page A cannot directly access the window.name value set on page B, and an intermediate page in the same domain as page A is required to act as a proxy for the communication between page A and page B.

a.html

<script> var data = null; var state = 0; var iframe = document.createElement('iframe'); iframe.src = "http://localhost:8081/b.html"; iframe.style.display = 'none'; document.body.appendChild(iframe); // set the value of c. HTML as window.name. // set the value of C. HTML as window.name. A.h HTML can pass the iframe. ContentWindow. Name get b.h windoa in HTML. The name of the value of the iframe. Onload = function () {if (state = = = 0) { iframe.src = "http://localhost:8080/c.html"; state = 1; }else if(state === 1) { data = iframe.contentWindow.name; Console. log(' Received data :', data); } } </script>Copy the code

b.html

<script>
    window.name = 'This is the data that's passed.';
</script>
Copy the code

Intermediate proxy pages, just need to keep to a page with domain, for example: http://localhost:8080/c.html.

7. window.postMessage

PostMessage is a new feature in HTML5 for cross-domain communication between pages.

The postMessage method takes two necessary arguments:

  • Message: data to be passed.
  • TargetOrigin: The target window domain name for data transfer. The value can be a specific domain name or the ‘*’ wildcard.

a.html

<iframe src="http://localhost:8081/b.html" style='display: none; '></iframe> <script> window.onload = function() { var targetOrigin = 'http://localhost:8081'; Var data = {name: 'wulinzaozao1 ', time: 2005, length: 81, address:' wulinzao2 '}; // Send window.frames[0]. PostMessage (data, targetOrigin); Window.addeventlistener ('message', function(e) {console.log('b.html :', e.data); }) } </script>Copy the code

b.html

<script> var targetOrigin = 'http://localhost:8080'; window.addEventListener('message', function(e) { if(e.source ! = window.parent) { return; } // Receive data sent by A.html console.log(' messages sent by A.html :', e.ata); // Send a message to a.html parent. PostMessage (' ha ha, I'm page B, I got your message ', targetOrigin); }) </script>Copy the code

conclusion

  • Cross-domain problems may occur when resources with different protocols, domain names, and port numbers communicate with each other.

  • For security reasons, the browser’s same-origin policy restricts communication between different domains.

  • JSONP, CORS, and Server Proxy cross-domain solutions are used for data communication between the front and back ends. Other cross-domain solutions are mainly used for data communication between Windows.

  • JSONP supports only HTTP requests in GET mode.

  • CORS cross-domain resource requests require back-end support.

  • The Server Proxy directly lets the back-end Proxy send requests.

Afterword.

All cross-domain solutions have corresponding DEMO instances, which can be viewed in DEMO. To see how this works, install the HTTP-server module globally.

npm install -g http-server
Copy the code

In the spirit of learning and summarizing the attitude of writing the technical output, there are any mistakes and problems, please point out. For more technical output, check out my Github blog.

Sorted out some front-end learning resources, hoping to help people in need, address: learning resources summary.

reference

  • zhuanlan.zhihu.com/p/25778815
  • Segmentfault.com/a/119000001…
  • Segmentfault.com/a/119000000…
  • Juejin. Cn/post / 684490…
  • Juejin. Cn/post / 684490…