随身笔记
随身笔记

详解5种跨域方式及其原理(推荐)

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 跨域

 

http://mp.weixin.qq.com/s?__biz=MzAwNjI5MTYyMw==&mid=2651493337&idx=1&sn=120bd45026c18659b025232c95b06a69&chksm=80f19a11b78613076c53026bc3d7d8f4d0ac52701854f2c78072d8920998ac5506a07592e997&scene=0#wechat_redirect

 

 

随身笔记

详解5种跨域方式及其原理(推荐)
URL 结果 原因 http://store.company.com/dir2/other.html Success http://store.company.com/dir/inner/another.html Success https://store.company.com/se…
扫描二维码继续阅读
2016-11-11