解决前端跨域的9种方式

一、什么是跨域?

浏览器有同源策略限制,协议、域名、端口号三者一样就是同源,三者只要有一个不同就是跨域。

二、9种方式

1、JSONP

2、CORS

3、http proxy  

4、nginx反向代理

5、postMessage

6、socket.io

7、document.domain + iframe

8、document.name + iframe

9、location.hash + iframe

三、具体解决跨域的实现

1、JSONP (不常用)

原理:是利用<script>标签不存在跨域请求的限制

缺点:1、只能处理get请求 2、通过URl携带参数容易被劫持,不安全

举例:也可以动态的去创建<script>标签,原理在这随意发挥,只要是<script>标签即可

 文件1:index.html

<script src="./index.jsonp.js"></script>

文件2:index.jsonp.js

$.ajax({
    url: 'http://127.0.0.1:8001/list',
    method: 'get',
    dataType: 'jsonp', //=>执行的是JSONP的请求
    success: res => {
        console.log(res);
    }
});

后端接受请求参数,并返回客户端,客服端拿到数据后执行函数

2、CORS 跨域资源共享 (前端不需要做任何改变)

原理:后端设置可访问的请求源

缺点:1、设置具体地址,有局限性  2、设置多源(*)就不能允许携带cookie了

举例:

前端发送请求(axios是基于promise封装)

axios.get('http://127.0.0.1:3001/user/list')
            .then(result => {
                console.log(result);
            })

后端设置相关请求: *号为多源,也可以替换为具体地址

app.use((req, res, next) => {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Credentials", true);
    res.header("Access-Control-Allow-Headers", "Content-Type,Content-Length,Authorization, Accept,X-Requested-With");
    res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,HEAD,OPTIONS");
    if (req.method === 'OPTIONS') {
        res.send('OK!');
        return;
    }
    next();
});

3、http proxy  (常用)

原理:node + webpack + webpack-dev-server代理接口跨域

devServer: {
        port: 3000,
        progress: true,
        contentBase: './build',
        proxy: {
            '/': {
                target: 'http://127.0.0.1:3001',
                changeOrigin: true
            }
        }
    },

4、nginx反向代理 (不需要前端干啥)

server {
    listen       80;
    server_name  www.chenfang.com;
    location / {
        proxy_pass   www.chenfang.cn; #反向代理
        proxy_cookie_demo www.chenfang.cn www.chenfang.com;
        add_header Access-Control-Allow-Origin www.chenfang.cn;
        add_header Access-Control-Allow-Credentials true;
    }
}

5、postMessage

postMessage传递消息

onmessage接受消息

A页面
```
<iframe src="http://www.chenfang.com/B.html"></iframe>
<script>
    let iframe = document.querySelector('iframe');
    iframe.onload = function () {
        iframe.contentWindow.postMessage('chenfang', 'http://www.chenfang.com/');
    }
    window.onmessage = function (ev) {
        console.log(ev.data);
    }
</script>
```

B页面
```
window.onmessage = function (ev) {
    console.log(ev.data);
    ev.source.postMessage(ev.data+'@@', ev.origin);
}
```

6、WebSocket协议跨域

前端处理
```
<script src="./socket.io.js"></script>
<script>
let socket = io('http://127.0.0.1:3001/');
//=>连接成功处理
socket.on('connect', function() {
    //=>监听服务端消息
    socket.on('message', function(msg) {
        console.log('data from server:' + msg); 
    });
    //=>监听服务端关闭
    socket.on('disconnect', function() { 
        console.log('server socket has closed!');
    });
});
//=>发送消息给服务器端
socket.send("zhufengpeixun");
</script>
```

服务器端处理
```
//=>监听socket连接:server是服务器创建的服务
socket.listen(server).on('connection', function(client) {
    //=>接收信息
    client.on('message', function(msg) {
        //=>msg客户端传递的信息
        //...
        client.send(msg+'@@');
    });
    //=>断开处理
    client.on('disconnect', function() {
        console.log('client socket has closed!');
    });
});
```

7、基于iframe的 document.domain

缺点:只能实现:同一个主域,不同子域之间的操作

父页面A  http://www.chenfang.cn/A.html
```
<iframe src="http://school.chenfang.cn/B.html"></iframe>
<script>
    document.domain = 'chenfang.cn';
    var user = 'admin';
</script>
```
子页面B  http://school.chenfang.cn/B.html
```
<script>
    document.domain = 'chenfang.cn';
    alert(window.parent.user);
</script>
```

8、location.hash + iframe

A和C同源
A和B非同源

页面A
```
<iframe id="iframe" src="http://127.0.0.1:1002/B.html" style="display:none;"></iframe>
<script>
    let iframe = document.getElementById('iframe');
    //=>向B.html传hash值
    iframe.onload=function(){
       iframe.src = 'http://127.0.0.1:1002/B.html#msg=zhufengpeixun';
    }
    
    //=>开放给同域C.html的回调方法
    function func(res) {
        alert(res);
    }
</script>
```

页面B
```
<iframe id="iframe" src="http://127.0.0.1:1001/C.html" style="display:none;"></iframe>
<script>
    let iframe = document.getElementById('iframe');
    //=>监听A传来的HASH值改变,再传给C.html
    window.onhashchange = function () {
        iframe.src = "http://127.0.0.1:1001/C.html"+ location.hash;
    }
</script>
```

页面C
```
<script>
    //=>监听B传来的HASH值
    window.onhashchange = function () {
        //=>再通过操作同域A的js回调,将结果传回
        window.parent.parent.func(location.hash);
    };
</script>
```

9 、window.name + iframe

页面A
```
let proxy = function(url, callback) {
    let count = 0;
    let iframe = document.createElement('iframe');
    iframe.src = url;
    iframe.onload = function() {
        if(count===0){
          iframe.contentWindow.location = 'http://www.chenfang.cn/proxy.html';
          count++;
          return;
        }
        callback(iframe.contentWindow.name);
    };
    document.body.appendChild(iframe);
};

//请求跨域B页面数据
proxy('http://www.chenfang.cn/B.html', function(data){
    alert(data);
});
```

B页面
```
window.name = 'chenfang';
```
原文地址:https://www.cnblogs.com/chenfanga/p/11684285.html