前言
瀏覽器如何處理文件,文件的上載與下載到底是怎么回事?
前端的各種處理方式
- 傳統(tǒng)flash上傳
- 新增iframe框ajax上載
- 表單數(shù)據(jù)提交
- HTML5的新工具——File API
我們下面依次講一下它們的原理寻狂,主要是后兩者和后端如何處理
flash上傳
沒有了解過访娶,不做評(píng)論
iframe框上傳
通過新建一個(gè)隱藏的iframe框拴清,把數(shù)據(jù)放到這個(gè)iframe框架里泻蚊,然后把它提交到服務(wù)器端處理躲舌,服務(wù)器返回的信息也是有iframe框調(diào)用父框架的方法處理丑婿⌒孕郏總之,是很坑爹的羹奉。
表單數(shù)據(jù)提交
重點(diǎn)有兩個(gè)秒旋,一個(gè)是FormData的數(shù)據(jù)對(duì)象,一個(gè)是level2 的XHttpRequest對(duì)象诀拭。
表單數(shù)據(jù)
var form= new FormData();
form.append(field,file,filename);
//field是表單里的key迁筛,就類似于一般表單里的name,file文件對(duì)象耕挨,filename是傳送至服務(wù)器里的文件名细卧,一般缺省
只要FormData里含有文件時(shí),上傳時(shí)enctype就是multipart/form-data而非一般時(shí)的application/x-www-form-urlencoded筒占,指定了不一樣的編碼類型贪庙。
XHttpRequest對(duì)象
創(chuàng)建xhr對(duì)象
if (typeof XMLHttpRequest !== 'undefined') {
xhr = new XMLHttpRequest();
} else {
var v = [
"Microsoft.XmlHttp",
"MSXML2.XmlHttp.5.0",
"MSXML2.XmlHttp.4.0",
"MSXML2.XmlHttp.3.0",
"MSXML2.XmlHttp.2.0"
];
for (var i=0; i < v.length; i++){
try {
xhr = new ActiveXObject(v[i]);
break;
} catch (e){}
}
}
return xhr;
xhr發(fā)起請(qǐng)求
xhr.open(option.method,option.action);
xhr.overridemimeType('..');//設(shè)定content-type
xhr.send(form);
xhr處理事件
可以把xhr對(duì)象當(dāng)原生js對(duì)象看待,其方法的調(diào)用都符合原生對(duì)象的習(xí)慣和規(guī)律
xhr.addEventlistener('progress',function(evt){
if(evt.lengthComputable){
var complete=evt.loaded/evt.total | 0;
}
});
//progress事件在一次請(qǐng)求回話中定時(shí)觸發(fā)翰苫,常用做進(jìn)度條
//最重要的事件是readystatechange,xhr對(duì)象有0,1,2,3止邮,4五個(gè)狀態(tài)
//當(dāng)狀態(tài)為4的時(shí)候,回話結(jié)束奏窑,無論錯(cuò)誤還是獲得響應(yīng)
//狀態(tài)為4時(shí),status==200說明從服務(wù)器成功獲得響應(yīng)
xhr.onreadystatechange=function(evt){
if(this.readystate!==4) return;
if(this.state==200){success..}
else fail;
};
xhr的重要變量
- xhr.state
- xhr.readystatechange
- xhr.responseText导披,從服務(wù)器得到的響應(yīng),純文本格式埃唯,應(yīng)該進(jìn)一步解析
File API
瀏覽器的文件API只能讀本地文件而不能寫本地文件撩匕,其中最重要的是FileReader。
創(chuàng)建與讀取
var reader=new FileReader();
reader.readAsBinaryString(file);
reader.readAsText(file);
reader.readAsDataURL(file);
//DataURL是一種指向?yàn)g覽器緩存的base64編碼的字符串墨叛,可以用來預(yù)覽圖片
事件處理
其處理機(jī)制也是與原生js對(duì)象一致的
reader.onload//成功讀取
reader.onprogress//基本與前面的xhr的progress一致
reader.onloadend//無論是否成功止毕,結(jié)束使=時(shí)均會(huì)觸發(fā)
reader.onloadend=function(evt){
if(reader.error) return error;
return evt.target.result;
//evt.target指向reader,用this.result也應(yīng)該可以
};
上傳操作
xhr將類型設(shè)置為二進(jìn)制流
xhr.send(reader.result);
但是我在node的后端沒有找到好的插件來解析req,導(dǎo)致雖然我驗(yàn)證了這種方式真的上傳了文件(大形∈怠)滓技,但沒有實(shí)現(xiàn)文件寫到服務(wù)器磁盤,我個(gè)人認(rèn)為這才是文件上傳未來的主要模式棚潦。
后端處理
req=請(qǐng)求頭+請(qǐng)求體
請(qǐng)求頭會(huì)被立即解析令漂,而請(qǐng)求體不會(huì)
請(qǐng)求體中不僅包含了文件的內(nèi)容,還有文件的信息,實(shí)際上文件是一個(gè)可讀流對(duì)象叠必,還有它的各種屬性荚孵,我們解析之后才能把文件與文件,文件內(nèi)容與文件信息區(qū)分開來
對(duì)于一般的文本編碼纬朝,只要這樣做就可以了
var post='';
req.on('data',function(chunk){
post+=querystring.parse(chunk);
});
我們可以輕易地看到內(nèi)容
單對(duì)于二進(jìn)制數(shù)據(jù)就沒有這么簡(jiǎn)單了收叶,文件與文件之間是有特定的分隔符的,關(guān)于這一點(diǎn)共苛,cnode上有一篇文章講的很好判没,文章名是node-post文件上傳原理詳解,有興趣的可以閱讀隅茎。