第一份軟件開發工做的第一個星期(不算作試用期的一個星期,無薪水試用)。由於不是軟件專業,也沒有通過培訓和相關工做經驗。老闆不放心,但仍是讓我試一試。作的第一件事情就是上傳文件,實時看進度,而且上傳後預覽。預覽的文件類型有word,ppt,excel,flash,視頻按幀獲取預覽圖。office文件是在服務器端轉成html後顯示出來。html
作的還滿意,就留下來了,後來就在那個公司待了兩年。html5
沒解決的事情:web
上傳大文件,分塊上傳,瀏覽器原生不支持,須要藉助第三方插件。最根本的緣由就是瀏覽器端的js考慮的安全問題,不容許讀取文件內容。ajax
如今IE10和其餘主流瀏覽器支持html5了,js內置Filereader對象,websocket,這些聽聽都酷斃了。數組
重大意義的時刻:瀏覽器
我實現了原生分塊上傳,道路很是崎嶇,結果很美好。安全
這一實現標識着,瀏覽器將來無可替代的地位。服務器
我只介紹乾貨部分,其餘細節,相信有興趣的人已經知道了。websocket
首先,分塊上傳,必須能在js內讀取文件內容,filereader對象是關鍵。這是一個異步讀取方法,必須在onload事件內獲取文件內容。要真真的分塊上傳,靠onprogress讀取文件進度是不夠的,而且文件過大的時候瀏覽器會卡死。file的slice函數是關鍵,把文件內容分塊,每個onload事件觸發,標誌着一塊內容讀取完畢,且能夠在該事件內把文件進一步處理,如上傳。異步
FileReader有四個read方法,
asText,只建議用來讀取文本文件
asDataUrl,讀取到的媒體文件能夠直接用於src屬性,或者html文件內容也能夠讀成DataURL
asArrayBuffer,官方介紹說不能直接使用,須要藉助DataView,如int8Array或int32Array。對於webSocket.send方法而言,ArrayBuffer和Int32Array都是可接受類型,服務端都是byte[]類型接受;若是是普通的Array數組類型,send方法內部會先轉成字符串,服務端接受string類型,接受的內容形如[].join(',')轉換過的值。
webSocket.send方法在onload事件中調用:
client.send(this.result);
結合slice和onload事件分塊上傳的核心代碼:
var res = this.result; loaded += res.byteLength; if (loaded < fileSize)//繼續讀取下一塊 { readBlob(loaded); times += 1; console.log("next block,times:" + times); } else { //讀取完成 console.log("done loaded:" + loaded + ",size:" + fileSize); }
slice的使用方法:
function readBlob(start) { var blob = currentFile.slice(start, start + step); reader.readAsArrayBuffer(blob); }
關於服務端能夠接受的最大文件大小,主要由config的兩個屬性控制,MaxRequestLength和ReceiveBufferSize屬性
ws = new WebSocketServer();//實例化WebSocketServer var serverConfig = new ServerConfig(); var rootConfig = new RootConfig(); serverConfig.MaxRequestLength = 1024 * 1024 * 1024;//1MB serverConfig.ReceiveBufferSize = 8096; serverConfig.Ip = ip; serverConfig.Port = port; ws.Setup(rootConfig, serverConfig);
MaxRequestLength和ReceiveBufferSize與常見的屬性不同,不追求完美的話,MaxRequestLength設置爲你但願最大可上傳的文件大小便可,分塊上傳也不須要太大。根據測試兩個屬性是有關聯的,即便MaxRequestLength比上傳的內容小一點點,也是能夠上傳的。具體待有答案後再補充。
asBinaryString 如今不同意使用的方法,且IE中也沒有該方法。
若是服務器端,不支持websocket又不想使用第三方支持如superwebsocket這樣組件,能夠直接使用ajax真真分塊上傳,肯定是每次請求都會創建新的鏈接。
使用ajax上傳注意事項乾貨:
建議把arraybuffer轉成int32array,這樣客戶端轉換較快。服務器端用int32[]接收;若是int8array服務端也能夠用int32接收。
重點:async:false 保證順序;也能夠每次上傳的時候額外帶參序號,服務器端從新組裝順序。
Int8array的話,服務端能夠直接把每一個元素轉成byte
[System.Web.Mvc.HttpPost] public ActionResult File(int[] datas) { if (datas != null) { var d = datas.ToList().ConvertAll(x => (byte)x).ToArray(); } return Content("OK"); }
int32array的話,服務端能夠藉助bitconverter.getbytes(int)方法。
[System.Web.Mvc.HttpPost] public ActionResult File(int[] datas) { if (datas != null) { List<byte> bs = new List<byte>();//接收到的文件緩衝對象 for (int i = 0; i < datas.Length; i++) { foreach (var item in BitConverter.GetBytes(datas[i])) { bs.Add(item); } } } return Content("OK"); }
ajax客戶端上傳關鍵方法:
$.ajax("/Home/File", { data: { datas: new Int8Array(this.result) }, success: function (res) { console.log(res); }, async: false, type:"post" });
這個調用是位於FileReader的onload事件中。
這個只是一個文件分塊上傳的例子,更多的好處是實時通訊,如實時獲取服務器端處理進度,而不用重複請求,把長鏈接,輪詢,橋都拋在腦後吧。推送消息都成爲可能。
若是以爲有意義,別忘了點【推薦】