js實(shí)現(xiàn)文件上傳
四種常見的post數(shù)據(jù)類型
首先文件上傳首先想到的發(fā)post丐重,當(dāng)然還有其他的上傳協(xié)議望抽,我們這里只介紹發(fā)post丑罪。
post支持四種content-type:
- application/x-www-form-urlencoded
Content-Type 被指定為 application/x-www-form-urlencoded爪模;其次沃琅,提交的數(shù)據(jù)按照 key1=val1&key2=val2 的方式進(jìn)行編碼殴蹄,key 和 val 都進(jìn)行了 URL 轉(zhuǎn)碼究抓。
- multipart/form-data
Request URL:http://192.168.13.11:8080/fetch2/test/test3
Request Method:POST
Status Code:200 OK
Request Headers:
Accept:*/*
Accept-Encoding:gzip, deflate
Accept-Language:en-US,en;q=0.8
Connection:keep-alive
Content-Length:6010
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryk0in9FHBncyu30RT
Host:192.168.13.11:8080
Origin:null
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36
Request Payload
------WebKitFormBoundaryk0in9FHBncyu30RT
Content-Disposition: form-data; name="file1"; filename="main.cpp"
Content-Type: application/octet-stream
------WebKitFormBoundaryk0in9FHBncyu30RT--
首先生成了一個(gè) boundary 用于分割不同的字段,為了避免與正文內(nèi)容重復(fù)袭灯,boundary 很長很復(fù)雜刺下。然后 Content-Type 里指明了數(shù)據(jù)是以 mutipart/form-data 來編碼,本次請求的 boundary 是什么內(nèi)容稽荧。消息主體里按照字段個(gè)數(shù)又分為多個(gè)結(jié)構(gòu)類似的部分橘茉,每部分都是以 --boundary 開始,緊接著內(nèi)容描述信息姨丈,然后是回車畅卓,最后是字段具體內(nèi)容(文本或二進(jìn)制)。如果傳輸?shù)氖俏募瘢€要包含文件名和文件類型信息翁潘。消息主體最后以 --boundary-- 標(biāo)示結(jié)束。
RFC1867
- application/json
application/json這個(gè)Content-Type都比較熟悉筋现,當(dāng)然也可以把json放到formData中唐础;
RFC4657
- text/xml
參見RFC,也比較常見矾飞。
XML-RFC
實(shí)現(xiàn)文件上傳有2種方式
- 普通post請求
該請求指的是content-type是application/json或text/xml一膨,這種方式很簡單,讀取文件內(nèi)容洒沦,然后上傳即可豹绪,當(dāng)然,有很多局限性申眼; - 利用formdata
formdata文件上傳是以二進(jìn)制流形式上傳瞒津,且無需寫額外代碼。
- 創(chuàng)建formdata:
//添加form標(biāo)簽
<form enctype="multipart/form-data" method="post" name="fileinfo" id="myFormElement">
</form>
//創(chuàng)建formdata
var formElement = document.getElementById("myFormElement");
formData = new FormData(formElement);
//若有其他元素不在表單里的括尸,可以通過append添加
formData.append("bookid",$('#bookID'.val()));
- 使用formData發(fā)送文件
在HTML中要有一個(gè)包含了文件輸入框的form元素巷蚪,表單里元素的name一定要寫,最終形成formData時(shí)濒翻,是以name作為key值
<form enctype="multipart/form-data" method="post" name="fileinfo">
<label>書名:</label>
<input type="text" name="bookname" /><br />
<label>bookid:</label>
<input type="text" name="bookid" /><br />
<label>File to stash:</label>
<input type="file" name="file" />
</form>
<div id="output"></div>
<a href="javascript:sendForm()">Stash the file!</a>
如果直接在form里寫action的話屁柏,會刷新表單啦膜,同步請求。所以用發(fā)送異步post請求方式淌喻。
function sendForm() {
var oOutput = document.getElementById("output");
var oData = new FormData(document.forms.namedItem("fileinfo"));
//userName不在表單中
oData.append("userName", "lilei");
var oReq = new XMLHttpRequest();
oReq.open("POST", "stash.php", true);
oReq.onload = function(oEvent) {
if (oReq.status == 200) {
oOutput.innerHTML = "Uploaded!";
} else {
oOutput.innerHTML = "Error " + oReq.status + " occurred uploading your file.<br \/>";
}
};
oReq.send(oData);
}
你還可以不借助HTML表單,直接向FormData對象中添加一個(gè)File對象或者一個(gè)Blob對象:
data.append("myfile", myBlob);
你還可以使用jQuery來發(fā)送FormData,但必須要正確的設(shè)置相關(guān)選項(xiàng):
var fd = new FormData(document.getElementById("fileinfo"));
//userName不在表單中
oData.append("userName", "lilei");
$.ajax({
url: "stash.php",
type: "POST",
data: fd,
processData: false, // 告訴jQuery不要去處理發(fā)送的數(shù)據(jù)
contentType: false // 告訴jQuery不要去設(shè)置Content-Type請求頭
});