浏览器出于安全方面的考虑,只允许与本域下的接口交互。不同源的客户端脚本在没有明确授权的情况下,不能读写对方的资源。
但在实际运用中我们往往需要获取不同源的数据,以下为解决跨域问题获取不同源数据的几种方法
1. JSONP
一个网页可以从任何网页获得js文件,基于动态<script>标签,通过src属性设置跨域url,可以获得其他域的资源
JSONP是被包含在函数中的JSON,浏览器将JSONP作为JS解析(调用一个函数),跨域请求到的JSON作为回调函数的参数,形如:
callback({"name":"Jim"});
JSONP有两部分组成,回调函数和数据。回调函数是当响应到来时应该在页面中调用的函数,回调函数的名字一般在请求中指定;数据就是传入回调函数中的JSON数据
<script>
var load=document.querySelector('#load');
var shownews=document.querySelector('showNews);
load.addEventListener('click',function(){
var script=document.createElement("script");
script.src='http://a.song.com:8080/getSong?callback=getSong';//设置跨域url,回调函数名getSong
document.head.appendChild(script);
document.head.removeChild(script);//获取资源后动态<script>标签作用结束,可删除此节
});
function getSong(json){//定义回调函数
console.log(json);
}
</script>
2. CORS
跨域资源共享,允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
额外添加一个origin头部,其中包含了请求页面的源消息(协议、域名和端口),根据这个头部信息服务器来决定是否给予响应,例如:
-
request的当前域
- request发起请求
xhr.open('get', 'http://a.song.com:8080/getSong', true);
- 服务器设置允许请求的域
res.header("Access-Control-Allow-Origin", "http://localhost:8080");
-
头部信息匹配,跨域请求成功
3.postMessage
当前url:http://a.jrg.com:8080
<div class="main">
<input type="text" placeholder="http://a.jrg.com:8080/a.html">
</div>
<iframe src="http://localhost:8080/b.html" frameborder="0" ></iframe>
向其他域发送数据
<script>
//URL: http://a.jrg.com:8080/a.html
$('.main input').addEventListener('input', function(){
console.log(this.value);
window.frames[0].postMessage(this.value,'*');//发送数据,*表示任何域,也可精确到某个特定域名
})
当前域http://localhost:8080,接收来自http://a.jrg.com:8080域发送的消息
<script>
window.addEventListener('message',function(e) {//监听其他域发送过来的消息
$('.main input').value = e.data
console.log(e.data);
});
</script>
4.降域
当前页面的url:
URL: http://a.jrg.com:8080/a.html
向其他域请求资源:
URL: http://b.jrg.com:8080/b.html
降域实现
<script>
//URL: http://a.jrg.com:8080/a.html
document.domain = "jrg.com"
</script>
<script>
//URL: http://b.jrg.com:8080/a.html
document.domain = "jrg.com"
</script>