之前在Vue的项目里面用到过文件上传,封装好的组件用起来比较顺手,查询Element-UI文档,十八般武器样样都有,一顿操作猛如虎,一看……跑偏了(⊙o⊙)…,我的意思就是用框架实现比较简单,但是如果用jQuery的话,对原理可能会更了解一些,有需要的一起看下吧~

1. multipart/form-data

因为HTTP提供的是基于文本的通信协议,而上传文件传输的是二进制数据,所以需要使用multipart/form-data编码格式,其HTTP消息体格式如下:

------WebKitFormBoundaryb0GZcypmEqOvNHIY
Content-Deiposition: form-data; name="file"; filename="icon.png"
Content-Type: image/png

------WebKitFormBoundaryb0GZcypmEqOvNHIY

multipart/form-data的请求头包含一个特殊的头信息Content-Type,其值为multipart/form-data,另外需要规定一个内容分割boundary用于分割请求体中多个不同的内容:

Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryb0GZcypmEqOvNHIY

2. input选择并获取文件
<form>
  <input type="file" id="uplfile" name="uplfile"/>
  <button type="button" id="uplfileBtn">上传</button>
</form>
<form>
  <input type="file" id="uplfile" name="uplfile"/>
  <button type="button" id="uplfileBtn">上传</button>
</form>

type="file"的input有一个叫files的DOM属性,可以获取到所选的文件列表(Array),数组中每一个对象都是file类型,

var files = $("#uplfile").prop('files');
var files = $("#uplfile").prop('files');
3. jQuery上传文件

新版本的XMLHttpRequest对象可以使用FormData对象管理表单数据,可以帮我们进行二进制文件的multipart/form-data编码,如下:

$("#uplfileBtn").click(function(){
    var files = $("#uplfile").prop('files');
   
    var data = new FormData();
    data.append('file', files[0]);  //参数名:file
    
    $.ajax({
        url: URL,
        type: 'POST',
        data: data,
        cache: false, //禁止浏览器对该URL的缓存
        contentType: false,
        processData: false,
        success: function(){
            //后续操作
        }
    });
});
$("#uplfileBtn").click(function(){
    var files = $("#uplfile").prop('files');
   
    var data = new FormData();
    data.append('file', files[0]);  //参数名:file
    
    $.ajax({
        url: URL,
        type: 'POST',
        data: data,
        cache: false, //禁止浏览器对该URL的缓存
        contentType: false,
        processData: false,
        success: function(){
            //后续操作
        }
    });
});

contentType:jQuery中contentType默认为application/x-www-form-urlencoded,因此传入的data会被转为默认的HTTP编码,这里我们不需要这种转换,设置为false。

processData:jQuery会将传入的data对象转为字符串来发送HTTP请求,这里我们的data已经是FormData对象处理好的multipart/form-data编码,所以不需要转换,设置为false。

4. js中如何直接下载文件

通常在web前端需要下载服务端文件,都是通过指定<a>标签的href属性访问服务端URL来下载保存文件的,也可以在js中:

document.location.href = Url + '?fileName=' + value;
document.location.href = Url + '?fileName=' + value;

上面这种方法用的是HTTP的GET请求,只能通过URL传参,在相对复杂的场景中(需要传多个参数在服务端动态下载指定文件),即参数比较多的时候,我们想要能够通过ajaxPOST方式来传递参数。

但是用ajax请求的数据只能存放在JavaScript的内存中,可以通过js读取,无法保存到硬盘,因为JavaScript本身无法直接和硬盘交互。那么有什么方法可以实现呢?一向方法总比困难多,我们可以通过模拟Form表单的提交来实现POST请求下载文件,如下:

<form id="myform" action="http://blog.kwin.wang/test/xxx.do" method="post">
  <input type="hidden" name="type" value="trade"/>
  <input type="hidden" name="time" value="20180818"/>
  <input type="hidden" name="fileName" value="a.png"/>
</form>
<form id="myform" action="http://blog.kwin.wang/test/xxx.do" method="post">
  <input type="hidden" name="type" value="trade"/>
  <input type="hidden" name="time" value="20180818"/>
  <input type="hidden" name="fileName" value="a.png"/>
</form>

主动提交Form表单:

$("#myform")[0].submit();
$("#myform")[0].submit();