您的位置:首页 > Web前端

【前端】利用ajax实现伪文件异步上传下载

2015-11-25 15:20 609 查看
利用ajax可以实现很酷的效果,在不刷新页面的情况下提交表单、修改数据状态等等,可是如果表单里还有input:file可就惨了,ajax不支持文件的处理啊!

ajax是使用了浏览器内部的XmlHttpRequest对象来传输XML数据的。既然是Xml的数据传输,那么传输的数据肯定是文本的,而文件上传则需要传输二进制的数据,显然用ajax是不可能的。

可是ajax这么好用,大家也都习惯了这种开发和使用体验,试想如果form表单包含文件上传,那提交表单要刷新整个页面,提交成功还好,提交失败了表单数据可都没有了,这颗真难受。有没有什么办法能实现类似的逻辑呢?

请注意以下属性:form:target、iframe、parrent.callback() ,我们利用这些小属性,来完成伪·ajax上传下载文件吧。

<!-- 这是数据表单 -->
<form action="/upload" id="form1" method="post"  enctype="multipart/form-data" target="hidden_frame">
<input type="file" name="uploadfile" accept="*" />
<input type="submit" value="提交" />
</form>
<!-- 这是一个隐藏的iframe -->
<iframe name="hidden_frame" id="hidden_frame" style="display:none;"></iframe>
<script type="text/javascript">
// 这是接收回调的函数
function callback(status, message) {
alert(message);
}
</script>


上边是html的大致结构,form表单包含了input:file,target到一个隐藏的iframe,这个隐藏的iframe并没有做任何事情,最后是一个接受回调的函数叫callback。

接下来就是服务器这边的逻辑了。

/upload这个接口接收到请求之后,从request里获取上传文件,名字就是input的name,然后进行逻辑处理,最后返回html数据。

接下来重点来了:

response返回的时候需要设置ContentType:text/html;charset=UTF-8;并且把结果拼成js代码写入返回的流中。

response.setContentType("text/html;charset=UTF-8");
// status表示处理结果的状态码,message为对应的提示信息
response.getWriter().print("<script>parent.callback(status, message);</script>");


注意到返回的js片段,调用了parrent的callback函数。

这里的结果会返回到我们之前的隐藏iframe中,parent就是html主页面,callback就是我们提前写好的回调函数。

到这里,关于文件上传的技巧就说完了,接下来讲讲关于文件下载的问题。

关于文件下载,我在工作当中遇到最多的场景就是在xx后台,有一堆查询条件,查询结果按表格展示,然后另外有个单独的按钮叫做“导出”,讲讲怎么使导出功能更加优雅。

首先,按了导出按钮之后server会进行对应的逻辑处理拿数据,之后把数据写到返回里,这中间一旦出现问题就只能返回错误的提示信息了。

这个逻辑有没有跟上边上传的情形很像呢? 我们利用类似的逻辑,来实现带错误提示的文件下载。

首先先上html代码片段

<!-- 查询表单 -->
<form action="/search" method="post" id="searchForm">
<input name="query1" type="input" />
<input name="query2" type="input" />

<input type="button" id="search" value="查询" />
<input type="button" id="export" value="导出" />
</form>
<!-- 隐藏的iframe -->
<iframe name="hidden_frame" id="hidden_frame" style="display:none;"></iframe>

<script type="txt/javascript" src="jquery-1.11.3.min.js"></script>
<script type="text/javascript">
$('input#search').bind('click',function(){
$('#searchForm').attr('action','');
$('#searchForm').attr('target','');
$('#searchForm').submit();
})
$('input#export').bind('click',function(){
$('#searchForm').attr('action','/export');
$('#searchForm').attr('target','hidden_frame');
$('#searchForm').submit();
})

// 这是接收回调的函数
function callback(status, message) {
alert(message);
}
</script>


代码分三部分,第一部分是查询表单,有一些查询参数,两个按钮分别是查询和导出。第二部分是一个隐藏的iframe,作用跟最上边的例子一样。第三部分是js代码,包含了3个方法,第一个定义查询按钮的行为-重置了form的target和action,第二个定义了导出的target和action,最后是接收回调的函数

请求到了服务器之后进行处理,查询逻辑就走查询的流程,把数据返回后展示到页面;导出的话有3种可能,有数据、没有数据、出现异常,如果要把状态都反馈到前端,那么这么做试试:

首先,异常和没有数据的情况,都可以按上传文件的返回方式,把处理结果的状态和信息封装到js片段,通过parent.callback返回前端。

response.setContentType("text/html;charset=UTF-8");
// status表示处理结果的状态码,message为对应的提示信息
response.getWriter().print("<script>parent.callback(status, message);</script>");


如果有数据,那么需要在服务器端把数据写入返回流,并且把response的contentType置为application/x-download,代码示意

response.setContentType("application/x-download");
// 描述,filename字段可以设置导出文件的名字,注意URLEncode处理下才可以支持中文
response.setHeader("Content-Disposition","attachment;filename=exportfilename");
// status表示处理结果的状态码,message为对应的提示信息
OutputStream stream = response.getOutputStream();
// infobytes是需要导出的数据
byte[] infobytes = new byte[100];
stream.write(infobytes);
stream.flush();


这样如果有数据,前端收到请求之后就会走浏览器的下载流程,如果没有数据或者出现异常,可以在不刷新页面的情况下给出提示。

注:以上代码的后端逻辑是以java为基础的伪代码,需要转化下才能真正使用
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: