AJAX可以进行数据的异步请求,但对于文件和跨域问题却束手无策。
Jsonp可以进行跨域数据的异步请求,但同样不能使用于文件。
<form>表单可以进行跨域数据和文件的上传,但却会使页面跳转。
那么如何同时实现“异步”+“跨域”+“文件”+“返回值”这几个特性呢?方法如下:
原理:
将<form>表单通过一个iframe来submit,也就是将<form>的target属性设置为一个iframe的id,这样<form>的action URL就会在这个iframe中打开,那么服务器的返回数据也就会输出到iframe中了。最后再通过主页面与iframe之间的交互完成对返回数据的读取(这涉及到跨域问题,文章后面将介绍此问题的解决方法)。
基本结构:
前端部分(当前域名:www.test.com,与form中的action域名相同)
1 |
< form action = "http://www.test.com/io.php" method = "POST" enctype = "multipart/form-data" target = "upload" > |
3 |
< input type = "file" name = "upload_file" /> |
5 |
< input type = "submit" value = "开始上传" /> |
9 |
< iframe name = "upload" style = "display:none" ></ iframe > // 注意,是name="upload",而不是id="upload" |
后台部分
3 |
move_uploaded_file( $_FILES [ 'upload_file' ][ 'tmp_name' ], 'upload/' . $_FILES [ 'upload_file' ][ 'name' ]); |
5 |
echo 'This data is from server!' ; |
优化结构一:
前端部分(当前域名:a.test.com,与form中的action域名不同)
01 |
< form action = "http://b.test.com/io.php" method = "POST" enctype = "multipart/form-data" target = "upload" > |
03 |
< input type = "file" name = "upload_file" /> |
05 |
< input type = "text" name = "script" value = "http://a.test.com/JS/iframe_control.src.js" style = "display:none" /> // 注意这里! |
07 |
< input type = "submit" value = "开始上传" /> |
11 |
< iframe name = "upload" style = "display:none" ></ iframe > // 注意,是name="upload",而不是id="upload" |
13 |
< script type = "text/javascript" > |
15 |
document.domain="test.com"; // 解决与iframe之间的跨域问题 |
后台部分
03 |
move_uploaded_file( $_FILES [ 'upload_file' ][ 'tmp_name' ], 'upload/' . $_FILES [ 'upload_file' ][ 'name' ]); |
05 |
$html = '<html><head>' |
07 |
. '<script src="' . $_POST [ 'script' ] . '" type="text/javascript"></script>' |
11 |
. 'This data is from server!' |
通过上面的优化,iframe从服务器接收到的内容中就多了一条<script>标签,这个标签的src是由<form>表单提交的,也就是说这个js文件可
以放在任何域名下,并且通过修改该js的内容来制定这个iframe的功能。比如,在其中调用document.doain="test.com"后,便可以与主页面
互相通信与控制了(主页面中也调用了document.domain="test.com",因此跨域限制被消除了)。
优化结构二:
前端部分(当前域名:www.a.com,与form中的action域名不同)
01 |
< form action = "http://www.b.com/io.php" method = "POST" enctype = "multipart/form-data" target = "upload" > |
03 |
< input type = "file" name = "upload_file" /> |
05 |
< input type = "text" name = "tmpurl" value = "http://www.a.com/tmp.html" style = "display:none" /> //注意这里! |
07 |
< input type = "submit" value = "开始上传" /> |
11 |
< iframe name = "upload" style = "display:none" ></ iframe > //注意,是name="upload",而不是id="upload" |
这次我们没有看到<script>标签,因为不再需要了,请继续看后台代码:
后台部分
3 |
move_uploaded_file( $_FILES [ 'upload_file' ][ 'tmp_name' ], 'upload/' . $_FILES [ 'upload_file' ][ 'name' ]); |
5 |
$data = 'This data is from server!' |
7 |
header( 'Location:' . $_POST [ 'tmpurl' ] . '?data=' . $_data ); |
与优化结构一不同的是,结构二中不再使用“指定document.domain为一级域名”来解除跨域限制,也不通过iframe的document内容来得到返
回数据,而是通过使iframe直接跳转至当前域名(通过$_POST['tmpurl']指定)来彻底取消跨域限制并且通过url的search部分传递返回数据。
两种结构的对比:
跨域:优化结构一只可解决一级域名相同的情况下的跨域情况,而优化结构二可解决任何跨域,比如百度与google之间。
数据:优化结构一的返回数据无大小限制,而优化结构二的返回数据必须小于2K(因为数据是通过RUL传输的)。