[Front-end technology] Talk about your understanding of cross-domain

1. Why do cross-domain problems occur

Due to the browser's same-origin policy restrictions. Same origin policy (Sameorigin policy) is a convention, it is the core and most basic security function of the browser. If the same origin policy is missing, the normal functions of the browser may be affected. It can be said that the Web is built on the basis of the same-origin policy, and the browser is only an implementation of the same-origin policy. The same-origin policy prevents the JavaScript scripts of one domain from interacting with the content of another domain. The so-called homology (that is, in the same domain) means that two pages have the same protocol (protocol) , host (host) and port number (port)

Second, what is cross-domain

When any one of the protocol, domain name, and port of a request url is different from the current page url, it is cross-domain

Current page url URL of the requested page Whether cross-domain the reason
http://www.test.com/ http://www.test.com/index.html no Same source (the same protocol, domain name, and port number)
http://www.test.com/ https://www.test.com/index.html Cross-domain Different protocols (http/https)
http://www.test.com/ http://www.baidu.com/ Cross-domain The main domain name is different (test/baidu)
http://www.test.com/ http://blog.test.com/ Cross-domain Different subdomains (www/blog)
http://www.test.com:8080/ http://www.test.com:7001/ Cross-domain The port number is different (8080/7001)

Three, what are the limitations of non-homologous

[1] Unable to read Cookies, LocalStorage and IndexedDB of non-same-origin webpages

[2] Unable to access the DOM of non-same-origin web pages

[3] Unable to send AJAX request to non-same source address

Four, cross-domain solutions

[1] Set document.domain to solve the problem of not being able to read cookies from non-same-origin webpages

 Due to restrictions of the JavaScript Same Origin Policy, scripts can only read the properties of windows and documents that have the same source as the document they belong to.

 For companies that already have a mature product system, different pages may be placed on different servers. These servers have different domain names, but have the same upper-level domain name.

  • For example, id.qq.com, www.qq.com, user.qzone.qq.com, they all have a public superior domain name qq.com. Cross-domain access between pages on these servers can be done through document.domain.

Pages with the same document.domain are equivalent to being on a server with the same domain name. If the protocol and port number are also the same, then they can access data across domains.

case study

(1) Visit the same-origin page

  1. Open https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Cookie
  2. In the f12 console window.open page  https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers
  3. Visit the document property of the returned window object and find that it can be accessed successfully, as shown in the following figure:

(2) The access protocol and port number are the same, and the domain name is inconsistent, but the page with the same upper-level domain name:

  1. Open id.qq.com , f12 open the console, window.open page:  www.qq.com ,
  2. The same access to the document property of the returned window object, it is found that the access fails, and it prompts that it is blocked from accessing the cross-domain form:

At this time, print document.domain of id.qq.com and document.domain of www.qq.com respectively, and find that the former is id.qq.com and the latter is qq.com

At this time, we manually set the document.domain of the id.qq.com page, set it to qq.com, visit the document of the window object of www.qq.com again, and find that the visit is successful:

[2] Cross-document communication API: window.postMessage()

Call the postMessage method to implement the parent window http://test1.com to send a message to the child window http://test2.com (the child window can also send messages to the parent window through this method)

It can be used to solve the following problems:

  • Data transfer between pages and new windows opened
  • Message passing between multiple windows
  • Page and nested iframe messaging
  • Cross-domain data transfer in the above three scenarios
// 父窗口打开一个子窗口
var openWindow = window.open('http://test2.com', 'title');
 
// 父窗口向子窗口发消息(第一个参数代表发送的内容,第二个参数代表接收消息窗口的url)
openWindow.postMessage('Nice to meet you!', 'http://test2.com');

Call the message event to monitor the message sent by the other party

// 监听 message 消息
window.addEventListener('message', function (e) {
  console.log(e.source); // e.source 发送消息的窗口
  console.log(e.origin); // e.origin 消息发向的网址
  console.log(e.data);   // e.data   发送的消息
},false);

【3】JSONP

JSONP is a common method for cross-origin communication between server and client. The biggest feature is simple application, good compatibility (compatible with lower versions of IE), but the disadvantage is that it only supports get requests, not post requests.

The core idea : The web page <script>元素requests JSON data from the server by adding one . After the server receives the request, it sends the data back in the parameter position of a callback function with a specified name.

① Native realization:

<script src="http://test.com/data.php?callback=dosomething"></script>
// 向服务器test.com发出请求,该请求的查询字符串有一个callback参数,用来指定回调函数的名字
 
// 处理服务器返回回调函数的数据
<script type="text/javascript">
    function dosomething(res){
        // 处理获得的数据
        console.log(res.data)
    }
</script>

② jQuery ajax:

$.ajax({
    url: 'http://www.test.com:8080/login',
    type: 'get',
    dataType: 'jsonp',  // 请求方式为jsonp
    jsonpCallback: "handleCallback",    // 自定义回调函数名
    data: {}
});

③ Vue.js

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

【4】CORS

CORS is the abbreviation for Cross-Origin Resource Sharing. It is a W3C standard and a fundamental solution for cross-origin AJAX requests.

  • Ordinary cross-domain request: only need to set Access-Control-Allow-Origin on the server side
  • Cross-domain request with cookie: both front and back ends need to be set

4.1 [Front-end settings] Determine whether there is a cookie according to the xhr.withCredentials field

① Native ajax

var xhr = new XMLHttpRequest(); // IE8/9需用window.XDomainRequest兼容
 
// 前端设置是否带cookie
xhr.withCredentials = true;
 
xhr.open('post', 'http://www.domain2.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);
    }
};

② jQuery ajax 

$.ajax({
   url: 'http://www.test.com:8080/login',
   type: 'get',
   data: {},
   xhrFields: {
       withCredentials: true    // 前端设置是否带cookie
   },
   crossDomain: true,   // 会让请求头中包含跨域的额外信息,但不会含cookie
});
 
 

③vue-resource

Vue.http.options.credentials = true

④ axios 

axios.defaults.withCredentials = true

4.2 [Server Settings]

The server-side support for CORS is mainly carried out by setting Access-Control-Allow-Origin. If the browser detects the corresponding settings, it can allow Ajax to conduct cross-domain access.

① Java background

/*
 * 导入包:import javax.servlet.http.HttpServletResponse;
 * 接口参数中定义:HttpServletResponse response
 */
 
// 允许跨域访问的域名:若有端口需写全(协议+域名+端口),若没有端口末尾不用加'/'
response.setHeader("Access-Control-Allow-Origin", "http://www.domain1.com"); 
 
// 允许前端带认证cookie:启用此项后,上面的域名不能为'*',必须指定具体的域名,否则浏览器会提示
response.setHeader("Access-Control-Allow-Credentials", "true"); 
 
// 提示OPTIONS预检时,后端需要设置的两个常用自定义头
response.setHeader("Access-Control-Allow-Headers", "Content-Type,X-Requested-With");

② Nodejs background

var http = require('http');
var server = http.createServer();
var qs = require('querystring');
 
server.on('request', function(req, res) {
    var postData = '';
 
    // 数据块接收中
    req.addListener('data', function(chunk) {
        postData += chunk;
    });
 
    // 数据接收完毕
    req.addListener('end', function() {
        postData = qs.parse(postData);
 
        // 跨域后台设置
        res.writeHead(200, {
            'Access-Control-Allow-Credentials': 'true',     // 后端允许发送Cookie
            'Access-Control-Allow-Origin': 'http://www.domain1.com',    // 允许访问的域(协议+域名+端口)
            /* 
             * 此处设置的cookie还是domain2的而非domain1,因为后端也不能跨域写cookie(nginx反向代理可以实现),
             * 但只要domain2中写入一次cookie认证,后面的跨域接口都能从domain2中获取cookie,从而实现所有的接口都能跨域访问
             */
            'Set-Cookie': 'l=a123456;Path=/;Domain=www.domain2.com;HttpOnly'  // HttpOnly的作用是让js无法读取cookie
        });
 
        res.write(JSON.stringify(postData));
        res.end();
    });
});
 
server.listen('8080');
console.log('Server is running at port 8080...');

③ PHP background

<?php
 header("Access-Control-Allow-Origin:*");

④ Apache needs to use the mod_headers module to activate the HTTP header settings, which is activated by default. You only need to add the following content to the configuration of <Directory>, <Location>, <Files> or <VirtualHost> in the Apache configuration file

Header set Access-Control-Allow-Origin *

 

 

Guess you like

Origin blog.csdn.net/qq_41893274/article/details/113615552