[TOC]

1. 为什么会出现跨域问题

出于浏览器的同源策略限制。同源策略(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互。所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),主机(host)和端口号(port)。
image.png
👮 CORS - 图2

2. 什么是跨域

当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域。

当前页面url 被请求页面url 跨域 原因
http://www.test.com/ http://www.test.com/index.html 同源(协议、域名、端口号相同)
http://www.test.com/ https://www.test.com/index.html 协议不同(http/https)
http://www.test.com/ http://www.baidu.com/ 主域名不同(test/baidu)
http://www.test.com/ http://blog.test.com/ 子域名不同(www/blog)
http://www.test.com:8080/ http://www.test.com:7001/ 端口号不同(8080/7001)
http://www.a.com/a.js http://a.com/b.js 同一域名,不同二级域名
http://www.a.com/a.js http://70.32.92.98/b.js 域名和域名对应IP(hosts没有映射情况下)

3. 非同源限制

  1. 无法读取非同源网页的Cookie、LocalStorage和IndexedDB。
  2. 无法接触非同源网页的DOM。
  3. 无法向非同源地址发送AJAX请求。

    4. 跨域解决方法

    1. 页面设置域名

    设置document.domain解决无法读取非同源网页的Cookie问题。因为浏览器是通过document.domain属性来检查两个页面是否同源,因此只要通过设置相同的document.domain,两个页面就可以共享Cookie(此方案仅限主域相同,子域不同的跨域应用场景。)
    该方式只能用于二级域名相同的情况下,比如 a.test.com 和 b.test.com 适用于该方式。只需要给页面添加 document.domain =’test.com’ 表示二级域名都相同就可以实现跨域。实现原理:两个页面都通过js强制设置document.domain为基础主域,就实现了同域。
    示例:页面a.zf1.cn:3000/a.html获取页面b.zf1.cn:3000/b.html中a的值

    // a.html
    <body>
    helloa
    <iframe src="http://b.zf1.cn:3000/b.html" frameborder="0" onload="load()" id="frame"></iframe>
    <script>
     document.domain = 'zf1.cn'
     function load() {
       console.log(frame.contentWindow.a);
     }
    </script>
    </body>
    // b.html
    <body>
    hellob
    <script>
      document.domain = 'zf1.cn'
      var a = 100;
    </script>
    </body>
    

    2. postMessage

    调用postMessage方法(跨文档通信 API:window.postMessage())实现父窗口“http://test1.com”向子窗口“http://test2.com”发消息(子窗口同样可以通过该方法发送消息给父窗口)。它可用于解决以下方面的问题:

  4. 页面和其打开的新窗口的数据传递。

  5. 多窗口之间消息传递。
  6. 页面与嵌套的iframe消息传递。
  7. 上面三个场景的跨域数据传递。 ```javascript // 父窗口打开一个子窗口 var openWindow = window.open(‘http://test2.com‘, ‘title’);

// 父窗口向子窗口发消息(第一个参数代表发送的内容,第二个参数代表接收消息窗口的url) openWindow.postMessage(‘Nice to meet you!’, ‘http://test2.com‘);

调用message事件,监听对方发送的消息:
```javascript
// 监听 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是服务器与客户端跨源通信的常用方法。最大特点就是简单适用,兼容性好(兼容低版本IE),缺点是只支持get请求,不支持post请求。核心思想:网页通过添加一个“

b.html为中间代理页,与a.html同域,内容为空。

// c.html(http://localhost:4000/c.html)

总结:通过iframe的src属性由外域转向本地域,跨域数据即由iframe的window.name从外域传递到本地域。这个就巧妙地绕过了浏览器的跨域访问限制,但同时它又是安全操作。
<a name="6M0HF"></a>
## 6. Nginx反向代理
实现原理类似于Node中间件代理,需要你搭建一个中转nginx服务器,用于转发请求。使用nginx反向代理实现跨域,是最简单的跨域方式。只需要修改nginx的配置即可解决跨域问题,支持所有浏览器,支持session,不需要修改任何代码,并且不会影响服务器性能。<br />实现思路:通过nginx配置一个代理服务器(域名与domain1相同,端口不同)做跳板机,反向代理访问domain2接口,并且可以顺便修改cookie中domain信息,方便当前域cookie写入,实现跨域登录。<br />先下载[nginx](http://nginx.org/en/download.html),然后将nginx目录下的nginx.conf修改如下:

// proxy服务器 server { listen 81; server_name www.domain1.com; location / { proxy_pass http://www.domain2.com:8080; #反向代理 proxy_cookie_domain www.domain2.com www.domain1.com; #修改cookie里域名 index index.html index.htm;

    # 当用webpack-dev-server等中间件代理接口访问nignx时,此时无浏览器参与,故没有同源限制,下面的跨域配置可不启用
    add_header Access-Control-Allow-Origin http://www.domain1.com;  #当前端只跨域不带cookie时,可为*
    add_header Access-Control-Allow-Credentials true;
}

}

最后通过命令行“nginx -s reload”启动nginx。

// index.html var xhr = new XMLHttpRequest(); // 前端开关:浏览器是否读写cookie xhr.withCredentials = true; // 访问nginx中的代理服务器 xhr.open(‘get’, ‘http://www.domain1.com:81/?user=admin‘, true); xhr.send(); // server.js var http = require(‘http’); var server = http.createServer(); var qs = require(‘querystring’); server.on(‘request’, function(req, res) { var params = qs.parse(req.url.substring(2)); // 向前台写cookie res.writeHead(200, { ‘Set-Cookie’: ‘l=a123456;Path=/;Domain=www.domain2.com;HttpOnly’ // HttpOnly:脚本无法读取 }); res.write(JSON.stringify(params)); res.end(); }); server.listen(‘8080’); console.log(‘Server is running at port 8080…’);

<a name="n6RL5"></a>
# 5. Chrome跨域
```powershell
cd C:\Program Files (x86)\Google\Chrome\Application
chrome.exe --args --disable-web-security --user-data-dir=C:\MyChromeDevUserData

参考

B站:各种方法解决跨域问题
https://www.bilibili.com/video/BV17K411M7JP?p=1
博客园:Vue proxy跨域代理
https://www.cnblogs.com/cengjingdeshuige/p/12659778.html
博客园:九种跨域方式实现原理(完整版)
https://www.cnblogs.com/fundebug/p/10329202.html
CSDN:什么是跨域?跨域解决方法
https://blog.csdn.net/qq_38128179/article/details/84956552
简书:Vue项目devServer.proxy代理配置详解
https://www.jianshu.com/p/8493282fe232