探索前端黑科技——通過 png 圖的 rgba 值緩存數據
作者:jrainlau
說起前端緩存,大部分人想到的無非是幾個常規的方案,比如cookie,localStorage,sessionStorage,或者加上indexedDB和webSQL,以及manifest離線緩存。除此之外,到底還有沒有別的方法可以進行前端的數據緩存呢?這篇文章將會帶你一起來探索,如何一步一步地通過png圖的rgba值來緩存數據的黑科技之旅。
原理
我們知道,通過為靜態資源設置Cache-Control和Expires響應頭,可以迫使瀏覽器對其進行緩存。瀏覽器在向後台發起請求的時候,會先在自身的緩存裡面找,如果緩存裡面沒有,才會繼續向伺服器請求這個靜態資源。利用這一點,我們可以把一些需要被緩存的信息通過這個靜態資源緩存機制來進行儲存。
那麼我們如何把信息寫入到靜態資源中呢?canvas提供了.getImageData()方法和.createImageData()方法,可以分別用於讀取和設置圖片的rgba值。所以我們可以利用這兩個API進行信息的讀寫操作。
接下來看原理圖:
當靜態資源進入緩存,以後的任何對於該圖片的請求都會先查找本地緩存,也就是說信息其實已經以圖片的形式被緩存到本地了。
注意,由於rgba值只能是[0, 255]之間的整數,所以本文所討論的方法僅適用於純數字組成的數據。
靜態伺服器
我們使用node搭建一個簡單的靜態伺服器:
constfs=require( fs )
consthttp=require( http )
consturl=require( url )
constquerystring=require( querystring )
constutil=require( util )
constserver=http.createServer((req,res)=>{
letpathname=url.parse(req.url).pathname
let realPath= assets +pathname
console.log(realPath)
if(realPath!== assets/upload ){
fs.readFile(realPath,"binary",function(err,file){
if(err){
res.writeHead(500,{ Content-Type : text/plain })
res.end(err)
}else{
res.writeHead(200,{
Access-Control-Allow-Origin : * ,
Content-Type : image/png ,
ETag :"666666",
Expires : Mon, 07 Sep 2026 09:32:27 GMT
})
res.write(file,"binary")
res.end()
}
})
}else{
let post=
req.on( data ,(chunk)=>{
post+=chunk
})
req.on( end ,()=>{
post=querystring.parse(post)
console.log(post.imgData)
res.writeHead(200,{
Access-Control-Allow-Origin : *
})
letbase64Data=post.imgData.replace(/^data:image/w+;base64,/,"")
letdataBuffer=newBuffer(base64Data, base64 )
fs.writeFile( assets/out.png ,dataBuffer,(err)=>{
if(err){
res.write(err)
res.end()
}
res.write( OK )
res.end()
})
})
}
})
server.listen(80)
console.log( Listening on port: 80 )
這個靜態資源的功能很簡單,它提供了兩個功能:通過客戶端傳來的base64生成圖片並保存到伺服器;設置圖片的緩存時間並發送到客戶端。
關鍵部分是設置響應頭:
res.writeHead(200,{
Access-Control-Allow-Origin : * ,
Content-Type : image/png ,
ETag :"666666",
Expires : Mon, 07 Sep 2026 09:32:27 GMT
})
我們為這張圖片設置了一年的Content-Type和十年的Expires,理論上足夠長了。下面我們來進行客戶端的coding。
客戶端
假設我們需要存儲的是32位的數據,所以我們為canvas設置寬度為8,高度為1。到底為什麼32位數據對應長度為8,是因為每一個像素都有一個rgba,對應著red,green,blue和alpha4個數值,所以需要除以4。
let keyString= 01234567890123456789012345678901
letcanvas=document.querySelector( #canvas )
letctx=canvas.getContext( 2d )
letimgData=ctx.createImageData(8,1)
imgData.data[i+]=parseInt(keyString[i])+50
imgData.data[i+1]=parseInt(keyString[i+1])+100
imgData.data[i+2]=parseInt(keyString[i+2])+150
imgData.data[i+3]=parseInt(keyString[i+3])+200
}
ctx.putImageData(imgData,,)
首先我們假設需要被緩存的字元串為32位的01234567890123456789012345678901,然後我們使用.createImageData(8, 1)生成一個空白的imgData對象。接下來,我們對這個空對象進行賦值。為了實驗效果更加直觀,我們對rgba值都進行了放大。設置完了imgData以後,通過.putImageData()方法把它放入我們的canvas即可。
我們現在可以列印一下,看看這個imgData是什麼:
// console.log(imgData.data)
[50,101,152,203,54,105,156,207,58,109,150,201,52,103,154,205,56,107,158,209,50,101,152,203,54,105,156,207,58,109,150,201]
接下來,我們要把這個canvas編譯為一張圖片的base64並發送給伺服器,同時接收伺服器的響應,對圖片進行緩存:
if(data=== OK ){
letimg=newImage()
img.crossOrigin="anonymous"
img.onload=()=>{
console.log( 完成圖片請求與緩存 )
ctx.drawImage(img,,)
console.log(ctx.getImageData(,,8,1).data)
}
}
})
結果分析
開啟伺服器,運行客戶端,第一次載入的時候通過控制台可以看到響應的圖片信息:
200 OK,證明是從服務端獲取的圖片。
關閉當前頁面,重新載入:
200 OK (from cache),證明是從本地緩存讀取的圖片。
接下來直接看rgba值的對比:
源數據:[50,101,152,203,54,105,156,207,58,109,150,201,52,103,154,205,56,107,158,209,50,101,152,203,54,105,156,207,58,109,150,201]
緩存數據:[50,100,152,245,54,105,157,246,57,109,149,244,52,103,154,245,56,107,157,247,50,100,152,245,54,105,157,246,57,109,149,244]
之前得到的結論,源數據與緩存數據存在誤差的原因,經查證後確定為alpha值的干擾所致。如果我們把alpha值直接定為255,並且只把數據存放在rgb值內部,即可消除誤差。下面是改良後的結果:
源數據:[,1,2,255,4,5,6,255,8,9,,255,2,3,4,255,6,7,8,255,,1,2,255,4,5,6,255,8,9,,255]
緩存數據:[,1,2,255,4,5,6,255,8,9,,255,2,3,4,255,6,7,8,255,,1,2,255,4,5,6,255,8,9,,255]
因為我懶,只是把alpha值給定為255而沒有把循環賦值的邏輯進行更新,所以第4n位的元數據被直接替換成了255,這個留著讀者自行修改有空再改……
綜上所述,這個利用png圖的rgba值緩存數據的黑科技,在理論上是可行的,但是在實際操作過程中可能還要考慮更多的影響因素,比如設法消除服務端的誤差,採取容錯機制等。實際上也是可行的。
值得注意的是,localhost可能默認會直接通過本地而不是伺服器請求資源,所以在本地實驗中,可以通過設置header進行cors跨域,並且通過設置IP地址和80埠模擬伺服器訪問。
後記
說是黑科技,其實原理非常簡單,與之類似的還有通過Etag等方法進行強緩存。研究的目的僅僅為了學習,千萬不要作為非法之用。如果讀者們發現這篇文章有什麼錯漏之處,歡迎指正,也希望有興趣的朋友可以一起進行討論。
覺得本文對你有幫助?請分享給更多人
關注「前端大全」,提升前端技能
※webpack2 終極優化
※png的故事:隔行掃描演算法
※測試你的前端代碼–part2
※Firefox 54 為何默認開啟四進程?Mozilla:不犧牲內存佔用
TAG:前端大全 |
※TalkingData馬驥出席QCon,分享前端黑科技
※賓士又出黑科技!Digital Light投影大燈
※易建科技eKing Cloud通過Kubernetes全球一致性認證
※angelababy看了會尖叫的黑科技
※【潮評測】傳說中的最強黑科技 索尼Xperia Touch體驗
※Data Technology數據科技,顯示大數據在未來產業發展中的作用舉足輕重
※集索尼黑科技於一身的Xperia XZ2 Premium
※廣深同步首發!Apple Watch Series 3帶著最新的黑科技來了
※滴滴宣布科技戰略:AI for Transportation
※【CamLogic Is Back!】新領域的黑科技!索尼RX0
※Maison Margiela:充滿未來科技感的太空旅者
※科技脈動 | Apple的下一款產品是眼鏡、品牌在Coachella擁抱科技
※價格破萬!adidas Futurecraft 4D真是跑鞋黑科技嗎?
※時時科技-Google 暗示Android Wear會易名
※知名科技博主 Ben Thompson:Dropbox 的價值究竟有多高?
※ProPublica 為什麼是 Facebook、Amazon等科技巨頭最怕的新聞媒體?
※微軟黑科技:HoloLens用上MRTouch觸摸
※【秀場】Maison Margiela:充滿未來科技感的太空旅者
※Imagination Technologies 獨家視角:2018年CES上的科技趨勢
※Under Armour推出科技新作!這次adidas Futurecraft 4D真的有話說!