ajax请求总是不成功?浏览器的同源策略和跨域问题详解 jsonp
场景
为什么会有这样的问题?
想象一下如果隔壁老王根本不认识你,他的网站自己有各种用户接口、订单接口、文章接口,那么谁都可以把这些接口返回的数据直接放在自己的网站上了,还是实时的。
什么是同源
如果两个页面拥有相同的协议(protocol: http),端口(port: 80),和主机(host: xiaoming.com),那么这两个页面就属于同一个源(origin)。
解决方案
这里就不讲多年前的iframe、flash等方式了,只讲几个最常用到的方案
A.x.com 和 B.x.com 间的跨域
子域名不同也是会受到跨域限制的。这种问题最简单,只需要将页面声明为更高级的域就可以了。
最经典、高效、浏览器兼容最好的解决方案:JSONP
但是有一个致命的缺点:非常高的跨站脚本攻击风险,所以 DataV 是不支持这种方式的
看到JSONP这个名字很多人以为这是和JSON密切相关的一种用来跨域的黑科技,但实际上从跨域的视角看,跟JSON并没有一毛钱关系,他是利用了浏览器允许跨域加载 js 等资源来获取数据。
因为浏览器支持跨域加载 js 如 <script src="http://aliyun.com/....."></script>
,所以很简单,可以把数据包装成 js 就可以了。
这是数据,通过 script 加载到数据无法“执行”,更无法传给 ajax 的回调函数:
这是js脚本,只要将 callback
与 ajax 的回调函数做关联,就可以讲数据传给回调函数:
一、需要 callback 与 ajax 回调函数绑定;
二、需要数据服务器 配合 的。
三、只支持GET请求
四、数据服务器可以随意插入危险的脚本
后端以 php 为例,逻辑是获取浏览器传来一个参数作为callback包装数据:
大部分新浏览器都兼容的 CORS(Cross Origin Resource Sharing)
他的原理是隔壁老王主动告诉浏览器“别拦着小明,我们是亲戚……”
所以最简单的例子,就是在数据服务器返回的头信息中包含:
然而这个头信息并不支持枚举,那如果隔壁老王的亲戚太多就只能通过程序来动态得生成这个头信息了,以PHP为例:
Cookies
CORS默认是不带 cookie 信息的,如果要带上 cookie 需要添加 withCredentials 参数,以 jquery 为例: