思考一個問題
??用戶需要上傳和下載一個重要的資料文件威鹿,應該如何判斷用戶本次是否上傳成功和下載成功了呢剃斧?是否僅僅通過代碼來判斷當前次的請求發(fā)送結(jié)束或者收到數(shù)據(jù)結(jié)束就可以了嗎?
答案是否定的专普。文件的上傳與下載極易出錯悯衬,尤其涉及使用斷點續(xù)傳方式上傳或下載的文件。
因此非常有必要在客戶端與服務器之間通過一種驗證機制來確保文件上傳下載后的完整性檀夹。那怎么樣才能保證資源的完整性筋粗,處理辦法就是用MD5驗證文件的完整性!
??當客戶端上傳一個文件的時候炸渡,在請求body里面添加該文件的MD5值來告訴服務器娜亿,服務器接受文件完畢以后通過校驗收到的文件的MD5值與請求body里面的MD5值來最終確定本次上傳是否成功。
??當客戶端下載一個文件的時候蚌堵,在響應頭里面收到了服務器附帶的該文件的MD5值买决,文件下載結(jié)束以后,通過獲取下載后文件的MD5值與本次請求服務器返回的響應頭中的MD5值做一個比較吼畏,來最終判斷本次下載是否成功督赤。
你可能覺得不就是下載一個文件嗎?需要這么麻煩嗎泻蚊?
那我們還是一起看看一些其他人都是怎么做的吧躲舌。
??這里強調(diào)一下,使用MD5來校驗完整性還是非常有必要的性雄,例如該文件比較大没卸,一個請求并不能快速請求到整個文件羹奉。文件的下載過程是持續(xù)的,大部分瀏覽在下載支持斷點續(xù)傳請求方式的文件的時候约计,默認都是啟用了斷點續(xù)傳的方式來下載诀拭。
??既然使用斷點續(xù)傳,那么不用想煤蚌,每一次請求都需要就設置Content-Range這個頭部耕挨,設置range字節(jié)開始傳輸?shù)奈恢茫J是按字節(jié)算的),回應使用206狀態(tài)值尉桩,表示現(xiàn)在開始部分傳輸俗孝,回復Content-Length頭部,表示傳輸?shù)牟糠制墙。米止?jié)記,然后就與普通傳輸沒有區(qū)別了插勤。這里Content-Range這個頭部每次都不一樣沽瘦,它是通過瀏覽器在每次收一部分數(shù)據(jù)后不斷在更新的,文件下載后又涉及一個I/O操作农尖,更新緩存進度信息操作析恋,這樣即使用戶任何時候關(guān)閉了瀏覽器,下載打開瀏覽器盛卡,文件還是從最近一次操作的最后進度開始的助隧。既然這么復雜,那么這個過程其實就極易出錯滑沧。因此并村,很難確保下載后,通過拼接二進制數(shù)據(jù)產(chǎn)生的文件就一定是完整的滓技。因此驗證文件完整性必不可少哩牍。
??細心的朋友們以后在下載任何文件的時候,都可以關(guān)注一下是否有MD5有關(guān)的信息令漂。其實游戲里面的補丁膝昆,下載后是一定需要校驗的。設想一下叠必,用戶下載了一個不完整的補丁文件荚孵,去跟一個舊版本的游戲做補丁合成,生產(chǎn)的最終的新版本文件纬朝,一定是錯誤的收叶。那么游戲使用者基本上再也打不開這個游戲軟件了,只能刪除重新一個完整的新版本安裝包玄组。(用戶內(nèi)心一定是千萬只草泥馬奔騰而過????~)滔驾。其實在完整的補丁文件與舊版本做合并新版本的過程中也是容易出錯的谒麦,任何的差池都會導致最終合并后的最版本有可能是錯誤的,那么合并后再次進行一次校驗(需要服務器提供新版本完整包的MD5)也是非常有必要的哆致。如果整個過程都沒有問題绕德,那么恭喜本次下載補丁,合并補丁的過程是非常OK的摊阀,用戶僅僅下載了很小的補丁就實現(xiàn)了整個應用程序的完整安裝耻蛇。
那么你肯定想問,文件的MD5值究竟是什么胞此,它能表征寫什么信息呢臣咖?還是先度娘一下吧
MD5校驗和通過對接收的傳輸數(shù)據(jù)執(zhí)行散列運算來檢查數(shù)據(jù)的正確性。
??一個散列函數(shù)漱牵,比如 MD5夺蛇,是一個將任意長度的數(shù)據(jù)字符串轉(zhuǎn)化成短的固定長度的值的單向操作。任意兩個字符串不應有相同的散列值(即酣胀,有“很大可能”是不一樣的刁赦,并且要人為地創(chuàng)造出來兩個散列值相同的字符串應該是困難的)。
??一個 MD5校驗和通過對接收的傳輸數(shù)據(jù)執(zhí)行散列運算來檢查數(shù)據(jù)的正確性闻镶。計算出的散列值拿來和隨數(shù)據(jù)傳輸?shù)纳⒘兄当容^甚脉。如果兩個值相同,說明傳輸?shù)臄?shù)據(jù)完整無誤铆农、沒有被竄改過(前提是散列值沒有被竄改)牺氨,從而可以放心使用。
??MD5校驗可以應用在多個領域墩剖,比如說機密資料的檢驗猴凹,下載文件的檢驗,明文密碼的加密等岭皂。MD5校驗原理舉例:如客戶往我們數(shù)據(jù)中心同步一個文件精堕,該文件使用MD5校驗,那么客戶在發(fā)送文件的同時會再發(fā)一個存有校驗碼的文件蒲障,我們拿到該文件后做MD5運算歹篓,得到的計算結(jié)果與客戶發(fā)送的校驗碼相比較,如果一致則認為客戶發(fā)送的文件沒有出錯揉阎,否則認為文件出錯需要重新發(fā)送庄撮。
簡單總結(jié)一下:其實就是任何一個字符串或文件,無論是可執(zhí)行程序毙籽、圖像文件洞斯、臨時文件或者其他任何類型的文件,也不管它體積多大,都有且只有一個獨一無二的MD5信息碼烙如,并且如果這個文件被修改過么抗,它的MD5碼也將隨之改變。
??Message-Digest泛指字節(jié)串(Message)的Hash變換亚铁,就是把一個任意長度的字節(jié)串變換成一定長的大整數(shù)蝇刀。注意這里說的是“字節(jié)串”而不是“字符串”,因為這種變換只與字節(jié)的值有關(guān)徘溢,與字符集或編碼方式無關(guān)吞琐。
知道了原理,那就話不多說然爆,趕快操練起來吧!
md5sum命令是Linux平臺下面用來檢測文件完整性的給力工具站粟,維基百科是這樣來解釋 md5sum的:
md5sum是一種計算機程序狸眼,用于計算與校驗128位MD5哈希值泌射,此處MD5散列值(或校驗和)作一個文件的數(shù)字指紋使用瘩缆。理論上看偶器,正如其他散列算法一樣,一個MD5哈希值可對應無限個文件读规,但從現(xiàn)實的角度看宜咒,兩個不同的文件幾乎不可能有相同的MD5哈希值幌绍,除非其創(chuàng)建便是刻意為之修械。一般來說,任何對一個文件的非惡意變更都會導致其MD5哈希值改變检盼,因此md5sum一般用于檢查文件完整性肯污,尤其常用于檢測在文件傳輸、磁盤錯誤或其他無惡意涉入的情況下文件的正確性吨枉。
示例:
以linux下shell為環(huán)境示例蹦渣,以下文件皆于同一目錄下。
計算校驗值并輸出至hash.md5
$ md5sum filetohashA.txt filetohashB.txt filetohashC.txt > hash.md5
所得文件貌亭,文件內(nèi)包括了哈希值和對應的文件名柬唯。
$ cat hash.md5
595f44fec1e92a71d3e9e77456ba80d1 filetohashA.txt
71f920fa275127a7b60fa4d4d41432a3 filetohashB.txt
43c191bf6d6c3f263a8cd0efd4a058ab filetohashC.txt
Mac OS可以用md5命令
先看下使用說明
usage: md5 [-pqrtx] [-s string] [files ...]
操練起來:
~ md5 -s woaini
MD5 ("woaini") = 023299564b0db47d5f3e476a254d0c21
MD5命令不能將路徑設置為文件夾路徑,只能是某一個具體文件圃庭。
~ MD5 /Users/nuomi/Desktop/OmniPlan-3.3.3.dmg
MD5 (/Users/nuomi/Desktop/OmniPlan-3.3.3.dmg) = c0a01ff9c0a4f0691a46616ab71e3380
還是非常簡單的锄奢。
那么在實際的移動應用開發(fā)中,文件上傳剧腻、下載都是必不可少的功能~
在此附上一個我總結(jié)的一個iOS上使用OC寫的獲取文件MD5值得一個小工具拘央。github傳送門
建議大家在重要文件的上傳、下載時书在,一定要與后臺同學協(xié)商灰伟,添加對文件傳輸完整性的校驗。
純手工儒旬,歡迎點贊栏账、討論帖族。??