聊聊跨域

闲言

记得我在一篇博客中提到跨域问题,这里要说明的一点是,我们之前提到关闭浏览器的安全策略那套解决跨域的方法仅仅是为了便于hybrid开发能够在PC端进行接口调试,而实际上前端端或服务端是需要通过程序来处理跨域的,因为通过关闭浏览器安全策略这套方案并不现实。

什么是跨域

跨域这个概念相信不论做web开发或是移动开发都会接触到这个问题。跨域是指请求非同源的资源。同源是所有浏览器的一个策略,所谓同源指的是

1.协议相同
2.域名相同
3.端口相同

只要有一点不符即视为非同源。同源的目的是保证用户信息安全,试想若你浏览器打开着网银,又打开着另一个网站B,网站B可以读取你的CooKie(包含着隐私如存款余额,或者登录状态),那它完全可以冒充你在你的网银上做任何事。

两个非同源的网站相互会被限制,限制有三种:

1、Cookie、LocalStorage 和 IndexDB 无法读取。
2、DOM无法获得。
3、AJAX请求不能发送。

跨域解决方案

其实大家只要明白了跨域的含义,就很容易理解一些关于跨域的解决方案的思路了。
常见解决方案如下:

通过jsonp跨域

例如:
移动端QQ音乐首页的图片及图片链接的接口:

https://c.y.qq.com/musichall/fcgi-bin/fcg_yqqhomepagerecommend.fcg?g_tk=1928093487&inCharset=utf-8&outCharset=utf-8&notice=0&format=jsonp&platform=h5&uin=0&needNewCode=1

原生代码:

var jsonp2 = function (data) {
        console.log(data)
    }
var script = document.createElement('script');
script.src = "https://c.y.qq.com/musichall/fcgi-bin/fcg_yqqhomepagerecommend.fcg?g_tk=1928093487&inCharset=utf-8&outCharset=utf-8&notice=0&format=jsonp&platform=h5&uin=0&needNewCode=1&jsonpCallback=jsonp2";
document.head.parentNode.insertBefore(script, document.head);

Ajax:

$.ajax({
     url: "https://c.y.qq.com/musichall/fcgi-bin/fcg_yqqhomepagerecommend.fcg?g_tk=1928093487&inCharset=utf-8&outCharset=utf-8&notice=0&format=jsonp&platform=h5&uin=0&needNewCode=1",
    type: "GET",
    crossDomain: true,
    dataType: "jsonp", //指定服务器返回的数据类型
    jsonp: "jsonpCallback", // 与后台约定的回调函数名
    success: function (data) {
        console.log(data);
    }
  });

Jsonp优点:支持老式浏览器,服务器改造非常小,可以向不支持CORS的网站请求数据。
Jsonp缺点:只支持GET请求。

其他

  • document.domain + iframe跨域
  • location.hash + iframe
  • window.name + iframe跨域
  • postMessage跨域
  • 跨域资源共享(CORS,前后端分离的项目常用,需要了浏览器和服务器同时支持,目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。因此关键在与服务器需实现CORS接口)
  • nginx代理跨域(服务器端调用HTTP接口只是使用HTTP协议,不会执行JS脚本,不需要同源策略,也就不存在跨越问题。)
  • nodejs中间件代理跨域
  • WebSocket协议跨域(常见的库如socket.io)

大家可以参考这几篇博客,内容十分详细:

浏览器同源政策及其规避方法——阮一峰
跨域资源共享 CORS 详解——阮一峰
前端常见跨域解决方案(全)