文件上传
简单来说,文件上传的方式可以分为两种
- 同步上传文件(页面锁死,需要等待文件上传完毕,上传完之后页面需要刷新)
- 异步上传
同步上传文件
传统的上传文件方式就是form表单上传,这是属于同步上传。
1 | <form action="test.php" target="" method="post" enctype="multipart/form-data"> |
- 这里method,上传方式只能选择 post 。
- enctype这个属性管理的是表单的MIME,参数规定了在发送到服务器之前应该如何对表单数据进行编码方式。
- 常见的参数有application/x-www-form-urlencoded、text/plain和示例中的multipart/form-data,因为上传的文件都是非纯文本传输,所以指定的类型必须只能是multipart/form-data。
- 其中①application/x-www-form-urlencoded是默认值,
大家可能在AJAX里见过这个:xmlHttp.setRequestHeader(“Content-Type”,”application/x-www-form-urlencoded”);
这两个要做的是同一件事情,就是设置表单传输的编码。在AJAX里不写有可能会报错,但是在HTML的form表单里是可以不写enctype=”application/x-www-form-urlencoded”的,因为默认HTML表单就是这种传输编码类型。
- 而②multipart-form-data是用来指定传输数据的特殊类型的,主要就是我们上传的非文本的内容,比如图片或者mp3等等。
- ③text/plain是纯文本传输的意思,在发送邮件时要设置这种编码类型,否则会出现接收时编码混乱的问题,网络上经常拿text/plain和text/html做比较,其实这两个很好区分,前者用来传输纯文本文件,后者则是传递html代码的编码类型,在发送头文件时才用得上。
- ①和③都不能用于上传文件,只有multipart/form-data才能完整的传递文件数据。
用户选择文件后,点击提交按钮即可上传文件。但是点击开始上传文件后,页面会锁死,并在上传完毕后刷新页面。这样的上传方式局限还有不能多文件上传。
异步上传文件
说到异步,可能会有人说ajax能不能实现文件的异步上传呢?答案是不行,ajax与后端通信只能传送字符串,是无法传递实体文件的,所以用ajax无法实现直接文件上传,不过我们可以在页面插入一个iframe来模拟文本的异步提交。
iframe上传
具体的原理就是,在点击提交按钮时,动态的生成一个隐藏的iframe加入页面上,并且把form的target指向隐藏的iframe,服务端就可以收到我们上传的文件,并进行相应的操作,然后将操作结果返回给隐藏的 iframe,,然后前端部分可以用 iframe.contentWindow.document.body.innerHTML来获取后端返回的结果,进行相应的JSON.parse处理数据。
1 | /* |
缺点也是不能批量处理。
使用FromData对象发送文件
HTML5提出了XMLHttpRequest对象的第二版,从此ajax能够上传文件了。这是真正的”异步上传”,是将来的主流。上一节的iframe上传,可以用作老式浏览器的替代方案。
- 在使用 FormData 异步上传文件之前,让我们先来了解下 FormData 的相关知识。
初始化 FormData 对象
先创建一个空的FormData对象,然后使用append()方法向该对象里添加字段
1
2
3
4var oMyForm = new FormData();
oMyForm.append("username", "Groucho");
// fileInputElement中已经包含了用户所选择的文件
oMyForm.append("userfile", fileInputElement.files[0]);使用HTML表单来初始化一个FormData对象
1
2var formElement = document.getElementById("myFormElement");
var oReq = new XMLHttpRequest();
append() :给当前FormData对象添加一个键/值对.
1
2oid append(DOMString name, Blob value, optional DOMString filename);
void append(DOMString name, DOMString value);name:字段名称.
value:字段值.可以是,或者一个字符串,如果全都不是,则该值会被自动转换成字符串.
filename: (可选)指定文件的文件名,当value参数被指定为一个Blob对象或者一个File对象时,该文件名会被发送到服务器上,对于Blob对象来说,这个值默认为”blob”.1
2
3
4
5
6
7
8
9
10
11
12var oMyForm = new FormData();
oMyForm.append("username", "Groucho");
oMyForm.append("accountnum", 123456); // 数字123456被立即转换成字符串"123456"
// fileInputElement中已经包含了用户所选择的文件
oMyForm.append("userfile", fileInputElement.files[0]);
var oFileBody = '<a id="a"><b id="b">hey!</b></a>'; // Blob对象包含的文件内容
var oBlob = new Blob([oFileBody], { type: "text/xml"});
oMyForm.append("webmasterfile", oBlob);
- 使用FormData对象上传文件实例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32/*
* ajax上传代码,放在表单的submit事件回调函数中:
form.on('submit',function() {
// 此处进行ajax上传
fileUpload.bind($(this))
});
*
*/
//我们主要用的是FormData对象,它能够构建类似表单的键值对。
function fileUpload() {
// 检查是否支持FormData
if(window.FormData) {
var formData = new FormData();
// 建立一个upload表单项,值为上传的文件
formData.append('upload', document.getElementById('upload').files[0]);
//另一种使用HTML表单来初始化初始化FormData对象
// var formData = new FormData( $(this) );
// formData.append('upload')
var xhr = new XMLHttpRequest();
xhr.open('POST', $(this).attr('action'),true);
// 定义上传完成后的回调函数
xhr.onload = function () {
if (xhr.status === 200) {
console.log('上传成功');
} else {
console.log('出错了');
}
};
xhr.send(formData);
}
}
资料参考: