web前端_跨域问题方法总结

文章内容基于个人总结,如有问题欢迎评论。

1.何为跨域

关于网站的跨域问题,简单的说就是不同协议(如http|https)不同域名(如www.a.com|www.b.com|a.b.com)或者不同端口号(:3000|3001)之间的请求访问,都会产生同源限制导致请求失败。

2.解决方案

下面展示5种解决方案(包含代码及部分思路)

 1) jsonp 根据script标签请求不会产生同源限制的原理 (局限在于只能发送get请求,及请求长度有限制)

客户端:

<div id="jsonp"></div>

<script type="text/javascript">
     function jsonpCallBack(data) {
        document.getElementById('jsonp').textContent = 'jsonp跨域callback-' + JSON.stringify(data);
    }
</script>

<script src="http://localhost:3000/api/jsonp?jsonp=jsonpCallBack"></script>
View Code

服务器端:

router.all('/jsonp', function(req, res, next) {
    var callback = req.query.jsonp;
    var obj = {name: 'tom', hobby: [1,2,3]};
    res.send(callback ? callback + '(' + JSON.stringify(obj) + ')' : 'jsonp response');
});
View Code

思路: 在客户端先定义好callback方法,将方法作为url参数传到服务器端,服务器端返回方法调用并回传参数让客户端方法处理。

 2) cors跨域 设置Access-Control-Allow-[Origin|Methods|Headers]等参数开启跨域许可

客户端:

<div id="cors"></div>
<script type="text/javascript">
    fetch('http://localhost:3000/api/cors', { method: 'get', mode: 'cors', cache: 'default' })
        .then(res => res.json())
        .then(data => {
            document.getElementById('cors').textContent = 'cors跨域-' + data;
    });
</script>
View Code

服务器端:

router.all('/cors', function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");  // 最简设置
  res.json('cors response');
});
View Code

  3) iframe + window.name

客户端:

<div id="iframe"></div>
<iframe src="http://localhost:3000" style="display: none" onload="iframeOnload()"></iframe>

<script type="text/javascript">
    document.domain = 'localhost';

    function iframeOnload() {
        var iframe = document.getElementsByTagName('iframe')[0];
        var win = iframe.contentWindow;
        win.fetch('http://localhost:3000/api').then(res =>         
            res.json().then(data => {                
                document.getElementById('iframe').textContent = 'iframe跨域-' + data;
        }));
    };
</script>   
View Code

服务器端:

router.all('/', function (req, res, next) {
    res.json('api response');
});
View Code

思路: 比较重要的一步是iframe页和请求页需要设置相同的domain, 即代码中执行的document.domain = 'localhost'这一段。

 4) iframe + postMessage

客户端:

<div id="postMsg"></div>
<iframe src="http://localhost:3000" style="display: none" onload="postOnload()"></iframe>

<script type="text/javascript">
    document.domain = 'localhost';

    window.onmessage = function(e) {
        document.getElementById('postMsg').textContent = e.data;
        console.log('client window:' + e.data);
    }

    function postOnload() {
        var iframe = document.getElementsByTagName('iframe')[0];
        var win = iframe.contentWindow;
        win.postMessage('test', '*');
        // postMessage
        postMessage('postMsg response', '*');
    }
</script>
View Code

思路: 这里win.postMessage是给iframe发送消息,直接的postMessage是给自己发送消息。如果在iframe页面想给本页面发消息,则需要用window.parent.postMessage发送消息。

 5) nginx反向代理

 这个方式的实现就是修改下nginx配置,如

server {
    listen 3001;
    server_name localhost;

    location /api {
        proxy_pass http://127.0.0.1:3000/api;
    }
}
View Code

 通过这种设置就把本地3001端口的请求映射到3000端口去,然后就可以正常的发送之前同源限制的api接口了, 如客户端代码:

<div id="nginx"></div>
<script type="text/javascript">
    fetch('/api').then(res => res.json()).then(data => {
        nginx.textContent = 'nginx反向代理跨域-' + data;
    })
</script>
View Code

3. 总结

基本的几种方式就是这样,当然都是一些抛砖引玉的小实现思路,具体问题还是得具体分析的。然后,一些代码用到了像es6语法或者fetch api,有看不懂的。。还是补补课吧,毕竟还是比较通用流行的了。

原文地址:https://www.cnblogs.com/easyToCode/p/4978735.html