跨域通信/跨域上传浅析
web项目跨域问题主要包括跨域通信和跨域上传,下面对这两方面分别做一个分析,具体项目中用哪个方案要看项目具体需求。
跨域通信
- jsonp
- hash
- server proxy
- window.name
- cors
- postmessage
- redirect
jsonp
原理:发起一个GET请求,回调函数带到请求参数中,把数据发送过去
坏处:服务器需要支持jsoncallback参数
好处:业界比较通用的方案,包括打点等操作都可以用类似技术
浏览器支持:chrome/firefox/safari/opera/ie6+
client:
//jquery
$(function(){
$.ajax({
url: ‘http://bbb.com:8888/crossdomain/jsonp.php‘,
dataType: ‘jsonp‘,
jsonp : ‘callback‘, //指定callback参数名
data: {name: ‘ysj‘} //数据
}).done(function(result){
alert(result) // {code:200}
})
})
//实际请求:http://bbb.com:8888/crossdomain/jsonp.php?callback=jQuery111108173922670539469_1410615060808&name=ysj&_=1410615060809
//native js
var temp = document.createElement(‘script‘);
temp.src = ‘http://bbb.com:8888/crossdomain/jsonp.php‘
+ ‘?callback=jsonpCallback&name=ysj‘; //设置callback参数
document.body.appendChild(temp)
temp.parentNode.removeChild(temp);
function jsonpCallback(result) {
alert(result) // {code:200}
}
server:
$callback = $_GET[‘callback‘];
echo $callback . "({code:200})";
hash
原理:父页面把参数设置设置到子iframe的hash,子iframe监听hash变化,把响应的数据设置到父页面的hash
坏处:需服务器对应支持,目前hash比较常用于路由,用于通信不太合适
好处:无
浏览器支持:chrome/firefox/safari/opera/ie6+
代码略
server proxy:
原理:a域请求b域,在a域设置一个proxy服务器脚本页面,接受a的参数,在通过发起一个http请求拿b域的内容,再返回给a域
坏处:在a域服务器需要增加一个proxy页面
好处:比较通用的方案
浏览器支持:chrome/firefox/safari/opera/ie6+
代码略
window.name
原理:a域请求b域的页面,b加载完后设置响应数据到window.name,再重定向到a的一个页面,此时window.name并没有改变
坏处:b域需重定向到a域的一个处理页面
好处:无
浏览器支持:chrome/firefox/safari/opera/ie6+
代码略
cors(跨域资源共享):
原理:服务器设置可访问性Access-Control-Allow-Origin: *,浏览器ajax取数据
坏处:需要服务器特殊处理
好处:有比较好的未来
浏览器支持:chrome/firefox/safari/opera/ie10+
代码略
postmessage:
原理:利用html5的postmessage api跨域穿数据
坏处:兼容性
好处:有比较好的未来
浏览器支持:chrome/firefox/safari/opera/ie10+
代码在下面跨域上传中演示
redirect:
原理:a域iframe请求b域,把url带上,b域把response带上,返回到a域的handler页面
坏处:有安全隐患
好处:简单又浏览器支持良好的方案
浏览器支持:chrome/firefox/safari/opera/ie6+
代码在下面跨域上传中演示
跨域上传
- cors
- redirect
- postmessage
cors
原理:利用XMLHttpRequest2+FormData,服务器设置Access-Control-Allow-Origin: *,跨域资源访问这个特性,加上html5的FormData可以发送文件的特性。
坏处:需要服务器设置支持跨域访问 Access-Control-Allow-Origin: *
好处:又比较好的未来
浏览器支持:chrome/firefox/safari/opera/ie10+
client:
document.forms[0].onsubmit = function() {
var xhr = new XMLHttpRequest();
var data = new FormData(document.forms[0]);
xhr.open(‘POST‘ , this.action)
xhr.onload = function(){
console.log(xhr.responseText)
}
xhr.send(data)
return false
}
server:
header("Access-Control-Allow-Origin: *");
echo "{code:200}";
redirect
原理:a域表单提交到b域,a的表单target指向a域的一个iframe,b域重定向到a域的结果页面,把数据带上。需要浏览器发送一个redirect参数,服务器检查到有这个参数,则重定向到结果页面,把内容带到参数上面
坏处:服务器和客户端特殊参数redirect处理
好处:支持所有浏览器
浏览器支持:chrome/firefox/safari/opera/ie6+
client:
<form method="post" action="http://bbb.bbb.com:8888/crossdomain/redirect.php" target="_iframe">
<input type="hidden" name="redirect" id="redirect">
<input type="file" name="Filedata">
<button type="submit">submit</button>
</form>
<iframe id="_iframe" name="_iframe"></iframe>
document.forms[0].onsubmit = function() {
document.getElementById(‘redirect‘).value = window.location.href.replace(/\/[^\/]*$/,‘/result.html?%s‘); //设置redirect参数值
var iframe = document.getElementById(‘_iframe‘)
iframe.onload = function(){
console.log(iframe.contentDocument
? iframe.contentDocument.body.innerHTML
: iframe.document.body.innerHTML) // {code:200}
}
}
redirect页面
document.body.innerText=document.body.textContent=decodeURIComponent(window.location.search.slice(1)); //把参数中的数据写入文档
server:
$redirect = isset($_REQUEST[‘redirect‘]) ?
stripslashes($_REQUEST[‘redirect‘]) : null;
$json = ‘{code:200}‘;
//有redirect参数,则重定向。需要注意的是服务器需要设置一个白名单,符合的才给予重定向,否则有安全问题
if ($redirect) {
//页面重定向,把返回数据替换掉redirect url中的%s
header(‘Location: ‘.sprintf($redirect, rawurlencode($json)));
}
postmessage
原理:a域准备好参数通过postmessage发送到b域的postMessageAPI页面,这个页面把数据用XHR+FormData的方式提交a域请求的url,postMessageAPI再把返回的数据postmesage到a域的页面
坏处:b端服务器需准备一个postmessageAPI页面
好处:有比较好的未来
浏览器支持:chrome/firefox/safari/opera/ie10+
client:
<form method="post">
<input type="file" name="Filedata" id="file">
<button type="submit">submit</button>
</form>
<iframe src="http://bbb.com:8888/crossdomain/postMessage.html"></iframe>
$(‘form‘).submit(function(){
var iframe = $(‘iframe‘)[0];
//向iframe的postmessate api发送消息
iframe.contentWindow.postMessage({
url : ‘http://bbb.com:8888/crossdomain/postMessage.php‘,
dataType:‘json‘,
data : {
file : $(‘input[type=file]‘)[0].files[0] //把文件数据传过去
},
contentType:false,
processData:false
}, iframe.src)
return false;
})
//拿到postmessageAPI返回过来的消息
$(window).on(‘message‘, function(e){
var e = e.originalEvent;
alert(e.data) // {code:200}
})
postmesage.html/postmessagetAPI页面
//等待接受消息
$(window).on(‘message‘, function(e){
var e = e.originalEvent;
var options = e.data;
var truedata = options.data;
var formdata = new FormData()
for(var prop in truedata) {
formdata.append(prop,truedata[prop]);
}
options.data = formdata;
//向postmessage.php发送ajax请求,都在b域,不跨域
$.ajax(options).always(function(result){
//把响应数据再postmessage到请求的页面
e.source.postMessage(result.responseText, e.origin)
})
})
server: postMessaget.php
echo "{code:200}";
跨子域通用方案
原理:a域aaa.aaa.com,b域bbb.aaa.com。客户端和服务器返回都设置document.domain = ‘aaa.com‘
坏处:有安全隐患
好处:比较方便
浏览器支持:chrome/firefox/safari/opera/ie7+
server:
//可以设置为客户端传来的domain参数,但需要白名单
<echo> "<script>document.domain=‘aaa.com‘</script>";
<echo> "{code:200}";
此方案有个需要注意的地方:ie下面对长度小于5个字符的短域名不能设置domain,例如www.uc.cn
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。