1. Why does cross-domain exist?

The browser’s security mechanism is the same origin policy, which prevents malicious web pages from stealing data.

The cookie of A website, if B website can be accessed, B website can pretend to be A user after getting the cookie

The behavior of homologous restriction is

Cookie, LocalStorage, and IndexDB cannot be read. (2) DOM cannot be obtained. (3) AJAX requests cannot be sent.Copy the code

2. How to become cross-domain

Same protocol, same domain name, same port

Cross-domain requests are classified into simple requests and complex requests

A simple request must meet the following conditions

As long as the following two conditions are met, it is a simple request. (1) The request method is one of the following three methods: HEAD GET POST (2) HTTP header does not exceed the following fields: Accept accept-language content-language last-event-id content-type: Application/X-www-form-urlencoded, multipart/form-data, text/plain are limited to three values

If any of the above requirements are not met, it is a complex request

The partial response header for a simple request looks like this

Access-control-allow-origin:
  • If it is *, the browser will not send cookies, even if your XHR is set to withCredentials
  • Specify the domain
  • Dynamic request fields, where the server operation gets header.origin from the request
res.header("Access-Control-Allow-Origin", req.headers.origin);
Copy the code
Access-control-allow-credentials (optional)

This item indicates whether cookies are included in the request

Contains the true

Not included: No field is written

This should be consistent with the withCredentials property in the XmlHttpRequest2 object, which is true when withCredentials is true. When the withCredentials are false, this item is omitted

Access-control-expose-headers (optional)
Additional information available from the getResponseHeader() method in the XmlHttpRequest2 object. In general, the getResponseHeader() method can only get the following information: Cache-Control Content-language Content-type Expires last-Modified PragmaCopy the code

Complex request

A “pre-request” is sent first, and the server needs to return a “pre-reply” as a response.

A pre-request is actually a permission request to the server. The actual request is executed only when the pre-request is successfully returned.

The server return code is usually used with 100

HTTP status code 100: continue Initial request to accept, the client sends the rest

HTTP status code 101: Switching Protocols The server translates compliance with a client’s request to another protocol

The pre-request is sent in the form of OPTIONS, which also contains fields and contains two CORS specific items:

Access-control-request-method – This is the type of actual Request, which can be simple requests like GET, POST, PUT, DELETE, and so on. Access-control-request-headers – This item is a comma-separated list of the Headers used by the complex Request.

3. Master and subdomain names and knowledge points

A.com is a top-level domain name

Bbs.a.com is a subdomain name, also known as a multi-level domain name

Pay attention to

  • CSS reference font cross domain issues

  • Canvas. DrawImage has cross domain problems when drawing links. Set crossorigin to solve the problem

  • CSS styles are not affected by cross-domain issues (questionable)

4. How to solve cross-domain problems

Hash + iframe 4. Window. name + iframe 5. PostMessage 6. Cers-cross-origin Resource Sharing 7. Nginx proxy 8. Nodejs middleware proxy 9. WebSocket protocol Cross domain

JSONP

In order to reduce the load of the Web server, we separate static resources such as JS, CSS and IMG to another server with an independent domain name, and then load static resources from different domain names through corresponding tags in the HTML page, which is allowed by the browser. Based on this principle, we can dynamically create script. Request a reference url to achieve cross-domain communication

this.$http.jsonp('http://www.domain2.com:8080/login', {
    params: {},
    jsonp: 'handleCallback'
}).then((res) = > {
    console.log(res); 
})
Copy the code

Document.domain + iframe cross domain

This solution applies only to cross-domain scenarios where the primary domain is the same and the subdomains are different

Implementation principle: two pages through JS forced document.domain as the base of the primary domain, to achieve the same domain

1.) parent window :(www.domain.com/a.html)

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

2.) sub-window :(child.domain.com/b.html)

<script>
    document.domain = 'domain.com';
    // Get the variables in the parent window
    alert('get js data from parent ---> ' + 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 (www.domain1.com/a.html)

<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>
Copy the code

2.) B.HTML (www.domain2.com/b.html)

<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>
Copy the code

3.) C. HTML (www.domain1.com/c.html)

<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>
Copy the code

Window. name + iframe cross domain

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).

1.) A.HTML (www.domain1.com/a.html)

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);
});
Copy the code

2.) proxy. HTML: www.domain1.com/proxy… Intermediate proxy page, same domain as A.HTML, content is empty.

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

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

PostMessage cross-domain

PostMessage is an API in HTML5 XMLHttpRequest Level 2, and is one of the few window properties that can operate across domains. It can be used to solve the following problems: A.) data transfer of the page and the new window it opens b.) message transfer between multiple Windows c.) page and nested iframe message transfer (game box) d.) cross-domain data transfer of the three scenarios above

Usage: The postMessage(data, Origin) method takes two arguments data: the HTML5 specification supports any primitive type or replicable 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 “/”.

1.) A.HTML (www.domain1.com/a.html)

<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' }; / / to send cross domain data domain2 iframe. ContentWindow. PostMessage (JSON. Stringify (data), 'http://www.domain2.com'); }; Window. addEventListener('message', function(e) {alert('data from domain2 --> '+ e.data); }, false); js </script>Copy the code

2.) B.HTML (www.domain2.com/b.html)

<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');
        }js
    }, false);
</script>
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. 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.

The front set

axios.defaults.withCredentials = true
Copy the code

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
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 {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 cookie domain name index index.html index.htm; # When accessing Nignx with middleware proxy interface such as Webpack-dev-server, there is no browser participation, so there is no source restriction. Add_header access-Control-allow-origin http://www.domain1.com; * add_header access-control-allow-credentials true; * add_header access-control-allow-credentials true; }}Copy the code
Cross domain of VUE framework (1 cross domain)

Cross domain using node + Webpack + webpack-dev-server agent interface. In the development environment, since the Vue rendering service and the interface proxy service are the same as Webpack-dev-server, there is no need to set headers cross-domain information between the page and proxy interface.

Webpack.config.js part configuration:

module.exports = {
    entry: {},
    module: {},...devServer: {
        historyApiFallback: true.proxy: [{
            context: '/login'.target: 'http://www.domain2.com:8080'.// Proxy cross-domain target interface
            changeOrigin: true.secure: false.// Used when the agent reports an error with some HTTPS service
            cookieDomainRewrite: 'www.domain1.com'  // The value can be false, indicating no change}].noInfo: true}}Copy the code

The WebSocket protocol is cross-domain

Reference [segmentfault.com/a/119000001…