接口跨域场景和解决方法

鄙人自封公司第一跨域解决大师,的确需要写一下关于跨域的事情。

前端调试,跨域太常见了。如下图:

chrome下跨域提示

跨域的原因,是浏览器的安全机制,不允许跨域互相调用,会提高网站的安全性。

前端跨域的最大模块,是 ajax 接口跨域

1、最简单的解决方法:jsonp

虽然 jQuery 将 jsonp 封装到了 ajax 方法里面,但是底层的代码调用,完全不是一样。

jsonp 的原理,就是通过 script 标签进行回调,原生的 jsonp 开发,会明显一些。

// 定义好回调方法

function qqq(data){

// do something

}

<script scr='http://xxx.com?callback=qqq'></script>

也就是相当于,服务端返回的代码,使用了 qqq 包了起来,然后调用了上面定义的那个 qqq 方法,实现了数据的跨域调用。

使用 jsonp 的注意点

需要与后台定义回调 key 值

jquery 的默认回调 key 值,是 callback,但是有的后台,为了数据的隐私性,会设置一个特殊的回调 key 值。这样的话,需要单独在 jquery ajax 里面,设置回调 key 值:jsonp: callback2,然后发出的请求,就是 http://xxx.com?callback2=qqq,如果不设置,或者设置的不对的话,请求会报错。

jsonp 的缺陷

  • 只支持 get 方式

    因为是动态创建 script。

    关于安全性要求比较高、数据量比较大的接口,就不太好了

  • 不支持同步

    只能是异步的。

    如果是需要获取到验证信息,并同时阻断其余操作的接口的话,无法进行。

可以支持缓存

jquery 创建 jsonp 的话,callback 的 value 值,默认会添加一大堆,防止缓存。其实也可以支持 callback 的 value 值固定,来配合运维同事做接口缓存,callback: qqq

类库支持

jquery、zepto 都支持 jsonp,vue 之前推荐的 ajax 库:vue-resource,也支持 jsonp。但是 vue 官方最近推荐的 ajax 库——axios,不支持 jsonp。

2、最省事的解决方法:后端设置跨域 response 头

服务器端对于 CORS 的支持,主要就是通过设置 Access-Control-Allow-Origin 来进行的。如果浏览器检测到相应的设置,就可以允许Ajax进行跨域的访问。

不同的后端语言,Java、PHP,都会有自己的设置方法,简单的很。

前端调试的时候,只需要抓包看这个接口的 response header 中,是否有 Access-Control-Allow-Origin 属性。

cookie 的附加

跨域请求,默认是不带上 cookie 信息的,因为不是一个域了,cookie 也有自己的域,要不然就乱了。但是很多情况下,我们是需要带上cookie信息的,这时候我们伟大的后端,需要多添加一个参数:Access-Control-Allow-Credentials:true,然后将前面的 Access-Control-Allow-Origin,改成具体的域名,这个是浏览器的另外一个安全要求,即不能使安全性过低,会有隐患。

然后前端在 ajax 的时候,需要进行单独设置:

crossDomain: true,withCredentials: true

3、在小范围很有效的解决方案:document.domain

这个仅适用于跟域名相同的跨域,如 a.lecloud.com,与 b.lecloud.com,如果不做处理的话,这俩是跨域的。

如果这俩域名下的JS文件,都做了 document.domain = 'lecloud.com',两者就不会跨域了,省了使用 jsonp、响应头设置了。如果不特殊处理的话,document.domain 的值是该域的完整域名。

该方案有隐患,之前遇到过的,使用了kindeditor,里面的上传图片,会创建一个 iframe,用于上传,该 iframe 使用了父域名的 domain,然后我又改写了父域名的 domain,造成了跨域。

4、双层 iframe 调用

这个一般适用于使用第三方登录、或者第三方什么的跨域调用,思路比较巧妙。

例如,我们乐视云的官网,使用了乐视网的第三方登录:www.lecloud.com,嵌套了 www.le.com 的 iframe,登录成功之后,www.le.com 动态创建一个 www.lecloud.com 的 iframe,并将值通过 src 传入。

  • 第一层:www.lecloud.com

    • 第二层:www.le.com

      • 第三层:www.lecloud.com

孙子层的 iframe 与第一层(爷爷层)的主页面,是同域的,可以进行数据的传输与方法的调用,通过 parent.parent.xxx() 调用,就 OK 了。这个一般利用情景比较少,一般自己公司开发的话,没有这么麻烦的调用方式。

5、后端做代理

如果我们请求一个其余网站的接口,无法进行跨域,可以通过后端同学,通过后端代码进行数据的拉取、透传,然后与前端同域调用。

6、html5 的 postMessage

这个鸟玩意,还没开始,就已经没人用了。

以上是 接口跨域场景和解决方法 的全部内容, 来源链接: utcz.com/z/264235.html

回到顶部