整理前端工作中的可复用代码(二):拓展spark-md5,支持计算网络文件md5
這里是《整理前端開發中的可復用代碼》中的第二篇,最初此系列文章的標題不是這個,但覺得標題要準確、明白一些,便做了修改。這里的經驗都來自作者的工作實踐,入了前端坑的摸爬滾打。
背景
在工作中接到一個需求,需要在瀏覽器端計算文件的md5值,然后在上傳文件時傳遞給后端儲存。按照以往的思路,后端只需要三兩行代碼即可實現,比如使用php中的md5_file。
$filename = "file.jpg";$md5 = md5_file($filename);echo $md5; 復制代碼然而文件并不是上傳到后端服務器,而是直接上傳到阿里云的oss。如果后端去請求oss上的文件計算md5,就容易造成服務器的壓力,所以計算文件md5的最好方式是交給客戶端實現。
盡管以前沒有接觸過瀏覽器端計算文件md5,但在谷歌、百度搜索一番后,便用spark-md5解決了這一需求。但如果事情就這樣結束了的話,就沒有后續計算網絡文件md5的想法,以及這篇文章的出現了。
接著計算本地文件md5的需求,又接到了一個需求。上傳的圖片要進行壓縮,壓縮使用plupload的自帶功能實現,而壓縮后的圖片md5已改變。經過一些時間還沒有找到解決方案,加上技術總監對我說項目后續要增加新東西,讓我最好在審核上傳資源的時候計算md5,這樣便開始了前端計算網絡文件md5的摸索。
File 對象
在谷歌、百度了N久之后,沒有找到一個準確的答案,包括flash方案。我想應該很少有在瀏覽器端計算網絡文件md5的需求或實現,也展開了自己的一些猜想。
第一應該先要有一個文件,然后從文件中計算md5,類似:
var file = new File(['www.domain.com/test.jpg'], 'test.jpg', {type: 'image/jpg'}); 復制代碼然而File對象并不接收url參數來生成文件,這里的url被當成字符串處理了,這不是想要的答案。
Blob 對象
Blob對象是一個類文件對象,File對象繼承于Blob對象,它們的用法類似,Blob也不能直接處理url為Blob對象。但要計算文件md5,需要FileReader讀取一個File或Blob對象,再由spark-md5進一步計算得出md5。
所幸在XMLHttpRequest中可以指定responseType為blod,請求文件并指定responseType為blod時,XMLHttpRequest將返回一個Blob對象,相關介紹可參考這里responseType,如下:
var request = new XMLHttpRequest();request.open('GET', url, true); request.responseType = 'blob'; request.onload = function() {//類似Blob(3275) {size: 3275, type: "image/vnd.microsoft.icon"}console.log(request.response); }; request.send(); 復制代碼至此,下一步便可以用spark-md5計算Blob對象來返回md5了(spark-md5官方示例)。
var request = new XMLHttpRequest();request.open('GET', url, true); request.responseType = 'blob'; request.onload = function() {var file = request.response;var blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice,chunkSize = 2097152, // Read in chunks of 2MBchunks = Math.ceil(file.size / chunkSize),currentChunk = 0,spark = new SparkMD5.ArrayBuffer(),fileReader = new FileReader();fileReader.onload = function (e) {spark.append(e.target.result);currentChunk++;if (currentChunk < chunks) {loadNext();} else {//獲取md5var md5 = spark.end();console.log(md5);} };fileReader.onerror = function () {console.error('文件讀取失敗'); };function loadNext() {var start = currentChunk * chunkSize,end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;fileReader.readAsArrayBuffer(blobSlice.call(file, start, end)); }loadNext(); }; request.send(); 復制代碼拓展spark-md5
通過上面的代碼,便實現了瀏覽器端js計算網絡文件的md5。而據spark-md5的使用方式,直接計算字符串md5時比較簡單:
SparkMD5.hash('hello world');//"5eb63bbbe01eeed093cb22bb8f5acdc3" 復制代碼如上只需要一行代碼即可,但在計算文件時略復雜些,代碼不利于復用。出于本系列文章整理可復用代碼的初衷,以及想要加入計算網絡文件md5功能,便封裝了一個插件。
- github地址:md5-util
- 演示:md5-util demo,下方附二維碼
使用方式:
<script src="md5-util.min.js"></script> 復制代碼//計算本地文件md5 SparkMD5.file(file,function(md5){console.log(md5) })//計算網絡文件md5 SparkMD5.file(url,function(md5){console.log(md5) }) 復制代碼這里參考過browser-md5-file,不同的是此插件只擴展了spark-md5,增加了file方法,spark-md5的所有方法均可在插件中使用。
瀏覽器兼容性
這里只討論計算網絡文件md5的兼容性,在pc端一些主流瀏覽器中測試了多次,得出的md5均是正確的。但由于XMLHttpRequest的responseType指定為blob,在移動端發現一些兼容性問題,已知ios uc瀏覽器及安卓5.1.1系統瀏覽器中返回blob異常,導致md5計算錯誤。
所以要計算網絡文件的md5時,請慎用。如果哪位大神有更好的解決辦法,還請分享下。
后記
一直以來web端計算md5的任務主要分配給后端,但漸漸的前端技術也能實現了,這意味著前端技術的逐漸繁榮。不過用“痛并快樂著”很適合描述前端開發,使用一個個新技術完成了以前不能實現的功能,也面臨著各種瀏覽器兼容性問題帶來的困擾。
還愿我們心懷向往,并砥礪前行吧。
此系列相關文章(同步更新):
總結
以上是生活随笔為你收集整理的整理前端工作中的可复用代码(二):拓展spark-md5,支持计算网络文件md5的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 面试官:react和vue有什么区别吗?
- 下一篇: 小猿圈Web前端开发学习路线