URL | 结果 | 原因 |
---|---|---|
http://store.company.com/dir2/other.html | Success | |
http://store.company.com/dir/inner/another.html | Success | |
https://store.company.com/secure.html | 属于跨域Failure | 协议不同 |
http://store.company.com:81/dir/etc.html | 属于跨域Failure | 端口不同 |
http://news.company.com/dir/other.html | 属于跨域Failure | 主机不 |
1.jsonp
这个方法也是最常用的方法来解决跨域的问题,直接上案例:
script标签是不受同源策略影响的,它可以引入来自任何地方的js文件。
而jsonp的原理就是,在客户端和服务端定义一个函数,当客户端发起一个请求时,服务端返回一段javascript代码,其中调用了在客户端定义的函数,并将相应的数据作为参数传入该函数。
//客户端设置
<body>
<button onclick="ajax()">点</button>
</body>
<script>
function ajax(){
var url = "http://localhost/1.php?jsonp_callback=jsonp_cb";
var script = document.createElement('script');
// 发送请求
script.src = url;
document.head.appendChild(script);
}
function jsonp_cb(data) {
alert(data);
}
</script>
服务端获取到jsonp_callback传递的函数名jsonp_cb,返回一段对该函数调用的js代码
//1.php服务器端
<?php
echo'jsonp_cb({"name": "story"})';
//或者 echo $_GET['jsonp_callback'].'({"name": "story"})';
?>
这里推荐使用jquery来做,它实现了兼容可以参考案例:《jquery ajax 跨域实例》
2.img ping
var img=new Image(); img.src='https://sdeno.com/xx.jpg'; //请求别的网站的图片,其实也是实现了跨域,只是本地客户端只能通过get方式来请求, img.onerror=function(){ //而客户端无法获取到服务器发来的信息 alert('error'); } img.onload=function(){ alert('success'); }
使用图片ping跨域只能发送get请求,并且不能访问响应的文本,只能监听是否响应而已,可以用来追踪广告点击。
3.window.name
window对象拥有name属性,它有一个特点:相同协议下,在一个页面中,不随URL的改变而改变
不管什么类似的数据赋值在window.name上都是转化为字符串
window.name = function(){} console.log(window.name) // "function(){}"
iframe拥有contentWindow属性,是给客户端使用的,专门用来获取服务器端那头设置的window.name的值。iframe的src第一次加载成功后已经能获取到window.name了,如果是跨域,还要再次把src修改为本地地址就可以在客户端使用iframe.contentWindow.name来获取跨域地址那边的window.name值
//客户端设置 <script> var url = "http://localhost/1.php"; //要跨域获取数据的网站 var iframe = document.createElement('iframe'); iframe.src = url; //iframe加载地址时,页面的另一头设置了window.name='值'; document.body.appendChild(iframe) var state = true; iframe.onload = function(){ //当iframe的页面完全加载完后触发 if(state === true){//这里使用if是避免了无限是刷新,因为要修改iframe的src地址为本地 iframe.src = ''; //再次修改src,要属于同源才能使用iframe.contentWindow.name获取到跨域网站设置的window.name值 state = false; }else if(state === false){ state = null var data = iframe.contentWindow.name;//在客户端使用iframe.contentWindow.name,就能获取到服务器那边设置的window.name的值,达到跨域的效果 console.log(data) } } </script>
//1.php 服务器端 <?php echo '<script> window.name = "{\"name\":\"story\"}"</script>'; ?>
4.postMessage
postMessage允许不同源之间的脚本进行通信,用法
otherWindow.postMessage(message, targetOrigin);
otherWindow 引用窗口 iframe.contentwindow 或 window.open返回的对象
message 为要传递的数据
targetOrigin 为目标源
// http://127.0.0.1:80 var iframe = document.createElement('iframe') iframe.onload = function(){ var popup = iframe.contentWindow popup.postMessage("hello", "http://127.0.0.1:5000"); } iframe.src = 'http://127.0.0.1:5000/lab/postMessage' document.body.appendChild(iframe) // 监听返回的postMessage window.addEventListener("message", function(event){ if (event.origin !== "http://127.0.0.1:5000") return; console.log(event.data) }, false) // http://127.0.0.1:5000/lab/postMessage window.addEventListener("message", function(event){ // 验证消息来源 if (event.origin !== "http://127.0.0.1") return; console.log(event.source); // 消息源 popup console.log(event.origin); // 消息源URI https://secure.example.net console.log(event.data); // 来自消息源的数据 hello // 返回数据 var message = 'world'; event.source.postMessage(message, event.origin); }, false);
推荐使用插件:《iframe跨域相互传值–messageEvent.js》
5.CORS
它允许一个域上的脚本向另一个域提交跨域 AJAX 请求。实现此功能非常简单,只需由服务器发送一个响应标头即可。
CORS(跨域资源共享)是一种跨域访问的机制,可以让AJAX实现跨域访问。它允许一个域上的脚本向另一个域提交跨域 AJAX 请求。实现此功能非常简单,只需由服务器发送一个响应标头即可。
//在服务器端 最前面添加 Access-Control-Allow-Origin: * // 允许来自任何域的请求 或者 Access-Control-Allow-Origin: http://funteas.com/ // 仅允许来自http://funteas.com/的请求
当客户端的ajax请求的url为其他域时,对于支持CORS的浏览器,请求头会自动添加Origin,值为当前host
var xhr = new XMLHttpRequest(); var url = 'http://bar.other/resources/public-data/'; xhr.open('GET', url, true); xhr.send();
CORS默认不发送cookie,如果要发送cookie,需要设置withCredentials
var xhr = new XMLHttpRequest(); xhr.withCredentials = true;
同时,服务端也要设置
Access-Control-Allow-Credentials: true
参考《推荐看php header 跨域》