UDN-企业互联网技术人气社区

板块导航

浏览  : 874
回复  : 12

[jQuery] 基于jQuery的ajax系列之用FormData实现页面无刷新上传

[复制链接]
genie1003的头像 楼主
发表于 2017-2-9 10:44:14 | 显示全部楼层 |阅读模式
  接着上一篇用jQuery的ajax方法向服务器发出get和post请求写,这篇主要写如何利用ajax和FormData实现页面无刷新的文件上传效果,主要用到了jQuery的ajax()方法和XMLHttpRequest Level 2的FormData接口。关于FormData,大家可以看MDN文档

  1,先看效果图
1.gif

  期望的功能和效果很简单:点击页面中的上传文件表单控件,选择文件后点击“ajax提交”,将文件上传至服务器,上传成功后,页面给出一个简单的提示。

  2,前端的代码

  看下html代码:
  1. <div class="box">
  2.             <div>
  3.                 <div class="item">
  4.                     <input type="file" name="myfile" style="font-size: 0.7rem;">
  5.                 </div>
  6.                 <div class="item">
  7.                     <button type="button" style="display: block; padding: 4px 18px;" class="btn-default">ajax提交</button>
  8.                 </div>
  9.                 <div class="item">
  10.                     <button type="submit" style="display: block; padding: 4px 18px;" class="btn-default">form提交</button>
  11.                 </div>
  12.             </div>
  13.             <div class="prompt" style="font-size: 0.7rem;"></div>
  14.         </div>
  15.         <script src="../../js/jquery-3.1.0.min.js"></script>
  16.         <script src="upload01.js"></script>
复制代码

  代码很简单,需要注意的是页面中没有用到form表单,那么怎么提交数据呢,答案是用FormData来模拟表单中的 <input type="file" name="myfile"> 控件。另外,页面中的样式没有写出来。下面来看下html中引入的upload01.js代码,这个是重点。

  upload01.js代码:
  1. $(function($) {
  2.     $('input[name=myfile]').on('change', function(e) {
  3.         $('button[type=button]').on('click', function(e) {
  4.             var formData = new FormData();
  5.             // formData.ppend(name, element);
  6.             formData.append('myfile', $('input[name=myfile]')[0].files[0]);
  7.             $.ajax({
  8.                 url: 'upload01.php',
  9.                 method: 'POST',
  10.                 data: formData,
  11.                 contentType: false, // 注意这里应设为false
  12.                 processData: false,
  13.                 cache: false,
  14.                 success: function(data) {
  15.                     if (JSON.parse(data).result == 1) {
  16.                         $('.prompt').html(`文件${JSON.parse(data).filename}已上传成功`);
  17.                     }
  18.                 },
  19.                 error: function (jqXHR) {
  20.                     console.log(JSON.stringify(jqXHR));
  21.                 }
  22.             })
  23.             .done(function(data) {
  24.                 console.log('done');
  25.             })
  26.             .fail(function(data) {
  27.                 console.log('fail');
  28.             })
  29.             .always(function(data) {
  30.                 console.log('always');
  31.             });
  32.         });
  33.     });
  34. });
复制代码

  (1) 下面解释下FormData,涉及到了代码的第4、6、10行。

  第4行 var formData = new FormData(); 实例化了一个空的FormData对象,可以认为它就是一个form表单,但现在里面什么控件都没有。

  第6行 formData.append('myfile', $('input[name=myfile]')[0].files[0]); ,给实例化的formdata对象添加一个控件,注意这里添加的是已有控件  (见html代码第4行)。

  FormData.append(name, value, filename)方法可以很方便的以“键-值”对的形式给FormData添加控件,注意第3个参数“上传文名”是可选的,它的具体语法和用法见FormData。

  第10行,将实例化的formData作为jQuery.ajax()方法data参数的值传递进去,提交给后端服务器。

  (2) 再解释下ajax()方法中的contentType、processData参数。

  contentType参数,发起http请求时设置的请求头中的contentType。jQuery.ajax()默认的值为:'application/x-www-form-urlencoded; charset=UTF-8',这个在大多数情况下都是适用的。

  但经过测试,保持默认时会报错,因为发送的数据中有input type="file"(上传文件),那么这时contentType应该设置为'multipart/form-data',但如果指定为这个类型服务端(php)就会报这个错误: Warning: Missing boundary in multipart/form-data POST data in Unknown on line 0 。具体原因现在还不清楚,所以这里先将contentType设置为false,即不让jQuery设置contentType。

  processData参数,根据jQuery.ajax()文档中的解释,默认情况下,jQuery会处理发送的数据,将数据按照'application/x-www-form-urlencoded'的要求转换为查询字符串,如果要发送的数据是DOMDocument或者不需要处理,就可以设置为false不让jQuery转换数据,我们这里要发送的数据其实就是DOMDocument。

  经过测试,如果保持默认(true)的话,在发起请求前js会报错: TypeError: 'append' called on an object that does not implement interface FormData.

  另外还有个dataType参数,期望从服务器中返回的数据格式,这里最好也不要指定,而是让jquery自己根据http响应头中的contentType判断,然后返回一个合适的数据类型。指定后不会影响后台程序的逻辑处理,但你在前端接收的数据很可能不是期望的数据,于是js就会报这一类错误: SyntaxError: JSON.parse: unexpected character at line 1 column 2 of the JSON data ,这个是将dataType指定为json后报的错误。

  3,后端的php代码

  后端服务器是nginx,用php来处理发送过来的数据,代码也很简单:
  1. <?php
  2. // var_dump($_REQUEST); // 为空数组
  3. // var_dump($_FILES); //不为空

  4. // 当使用FormData配合ajax上传文件时,$_REQUEST、$_POST都是空数组,php://input也是null
  5. if (isset($_FILES['myfile']) && !empty($_FILES['myfile'])) {
  6.     if (move_uploaded_file($_FILES['myfile']['tmp_name'], $_FILES['myfile']['name'])) {
  7.         echo '{"result": 1, "filename": "' . $_FILES['myfile']['name'] . '"}';
  8.     } else {
  9.         echo '{"result": 0}';
  10.     }
  11. }
复制代码

  代码的逻辑很简单这里就不多解释了。主要说下我在调试程序时遇到的问题,遇到的问题总结起来就一句话:当使用FormData配合ajax上传文件时,$_REQUEST、$_POST都是空数组,php://input也是null。可以看到,我在代码中的第2、3、5行也写了相关的注释。为什么$_REQUEST会是空呢?我查了些资料,但没找到原因,以后再找原因吧。

相关帖子

发表于 2017-2-9 10:44:55 | 显示全部楼层
经常看到”genie1003“发帖,辛苦了
使用道具 举报

回复

发表于 2017-2-11 23:42:11 | 显示全部楼层
其实js如果遇到web安全类的项目,那就又要做牺牲了,无法读写文件,访问受限。。。哎。。。
使用道具 举报

回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关于我们
联系我们
  • 电话:010-86393388
  • 邮件:udn@yonyou.com
  • 地址:北京市海淀区北清路68号
移动客户端下载
关注我们
  • 微信公众号:yonyouudn
  • 扫描右侧二维码关注我们
  • 专注企业互联网的技术社区
版权所有:用友网络科技股份有限公司82041 京ICP备05007539号-11 京公网网备安1101080209224 Powered by Discuz!
快速回复 返回列表 返回顶部