如何解决跨域

147 阅读2分钟

什么是跨域

当一个URL的协议、端口、域名任何一个与当前URL不同就是跨域。

为什么会出现跨域

这是由于浏览器的同源策略,它是浏览器最核心的最基本的安全功能,没有同源策略,浏览器的正常功能就会受到影响,web就是建立在同源策略的基础之上,同源策略会阻止一个新的域的JavaScript脚本和另一个域的主机进行交互,同源就是能在一个域的两个页面具有相同的协议、域名和端口号。

JSONP解决跨域

JSONP是服务器与客户端通信的常用方法,可以兼容IE,但就是不支持post请求。

  • 原生
<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({
    url: 'http://www.test.com:8080/login',
    type: 'get',
    dataType: 'jsonp',  // 请求方式为jsonp
    jsonpCallback: "handleCallback",    // 自定义回调函数名
    data: {}
})
  • Vue.js

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

CORS解决跨域

CORS是跨域资源共享的缩写,是W3C的标准。

  • 如果是普通的跨域请求,只要在服务端设置Access-Control-Allow-Origin
  • 带cookie的话,前后端都要进行设置
  • 原生

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

  • Vue.js中的axios
axios.defaults.withCredentials = true;
  • 服务端的后台需要设置Access-Control-Allow-Origin

window.postMessage()解决跨域

它可以解决:

  • 页面和打开的窗口的数据传递
  • 多窗口数据传递
  • 页面和嵌套的iframe传递
  • 跨域数据传递

// 父窗口打开一个子窗口
var openWindow = window.open('http://test.com', 'title');
 
// 父窗口向子窗口发消息(第一个参数代表发送的内容,第二个参数代表接收消息窗口的url)
openWindow.postMessage('Nice to meet you!', 'http://test.com')

调用message事件,监听对方发送的消息


// 监听 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);

proxy解决跨域

module.exports = {
  devServer: {
      proxy: {//解决跨域问题
          '/api': {
              // 此处的写法,目的是为了 将 /api 替换成 https://atimap.cn/
              target: 'https://atimap.cn/',
              // 允许跨域
              changeOrigin: true,
              ws: true,
              pathRewrite: {
                  '^/api': ''
              }
          }
      },
   
  }
}