摘要:對于第二種存儲方式,我們前端需要將其二進制流交由對象處理,然后通過的生成臨時賦值給屬性來顯示。當后端返回特定的圖片二進制流的時候,就像我第一里的情景再現說的,前端用容器接收。
前言
作為前端工程師 de 我們,日常少不了會跟圖片打交道。在各大電商平臺工作的前端工程師們,感受可能會更加的明顯。
以下是我之前跟圖片打交道踩到的坑,跟大家分享一下經驗。
一、情景再現用postman請求接口的時候,返回的是這個圖片(二進制)
在chrome的network查看的時候,返回的也是這個圖片(二進制)
可是,在debug打印的時候,返回的卻是亂碼
很明顯,數據的類型已經被改動了。思考原因,唯一有可能改變數據類型的地方是在axios。
我去翻看了一下axios的文檔,里面是這樣描述的
// `responseType` indicates the type of data that the server will respond with // options are "arraybuffer", "blob", "document", "json", "text", "stream" responseType: "json", // default
因此,亂碼出現的原因是因為:axios默認返回的是json文本形式,二進制圖片數據被強制轉換成了json文本形式。
找到了原因,解決方案就好辦了。我們在axios里面,responseType默認返回數據類型是json,將其改為返回數據類型blob。
export function miniprogramQrcode (params) { return axios.post( env.MI_URL + "/XXXX/XXX/XXXX", params, // 將responseType的默認json改為blob { responseType: "blob", emulateJSON: true }).then(res => { if (res.data) { return Promise.resolve(res.data) } else { throw res } }).catch(err => { return Promise.reject(err) }) }
接下來的問題是,如何處理blob對象,將其顯示在前端頁面呢?
代碼如下:
createMiniQrcode (blob) { let img = document.createElement("img") img.onload = function (e) { // 元素的onload 事件觸發后將銷毀URL對象, 釋放內存。 window.URL.revokeObjectURL(img.src) } // 瀏覽器允許使用URL.createObjectURL()方法,針對 Blob 對象生成一個臨時 URL。 // 這個 URL 以blob://開頭,表明對應一個 Blob 對象。 img.src = window.URL.createObjectURL(blob) document.querySelector(".imgQrCode").appendChild(img) }
是不是以為就這樣結束了? No, No, No. 了解如何解決問題還不夠,還需要透過表象進行發散思考。
二、 發散思考一般來說,圖片在后端的存儲方式分為兩種:
其一:可以將圖片以獨立文件的形式存儲在服務器的指定文件夾中,再將路徑存入數據庫字段中; 其二:將圖片轉換成二進制流,直接存儲到數據庫的 Image 類型字段中.
對于第一種存儲方式,我們前端直接將存儲路徑賦值給src屬性即可輕松顯示。
對于第二種存儲方式,我們前端需要將其二進制流交由blob對象處理,然后通過blob的API生成臨時URL賦值給src屬性來顯示。
兩種存儲方式都有對應的解決方案,似乎已經完美解決了關于圖片顯示的問題。但是,我們的業務場景是多樣且多變的。有時候我們也會遇到這樣的場景,比如圖片拖拽上傳插件后,自動返回給你了Blob對象,但不幸的是,你發現你又用了一個第三方的服務接口只接收 base64 格式的數據,是否有點欲哭無淚?
那么,圖片的三種表現形式url、base64、blob,三者之間是否可以轉化以滿足需求呢?
1. url 轉 base64url to base64 的方法封裝
// 原理: 利用canvas.toDataURL的API轉化成base64 urlToBase64(url) { return new Promise ((resolve,reject) => { let image = new Image(); image.onload = function() { let canvas = document.createElement("canvas"); canvas.width = this.naturalWidth; canvas.height = this.naturalHeight; // 將圖片插入畫布并開始繪制 canvas.getContext("2d").drawImage(image, 0, 0); // result let result = canvas.toDataURL("image/png") resolve(result); }; // CORS 策略,會存在跨域問題https://stackoverflow.com/questions/20424279/canvas-todataurl-securityerror image.setAttribute("crossOrigin","Anonymous"); image.src = url; // 圖片加載失敗的錯誤處理 image.onerror = () => { reject(new Error("圖片流異常")); }; }
你可以這樣調用:
let imgUrL = `http://XXX.jpg` this.getDataUri(imgUrL).then(res => { // 轉化后的base64圖片地址 console.log("base64", res) })2. base64 轉 blob
base64 to blob 的方法封裝
// 原理:利用URL.createObjectURL為blob對象創建臨時的URL base64ToBlob ({b64data = "", contentType = "", sliceSize = 512} = {}) { return new Promise((resolve, reject) => { // 使用 atob() 方法將數據解碼 let byteCharacters = atob(b64data); let byteArrays = []; for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) { let slice = byteCharacters.slice(offset, offset + sliceSize); let byteNumbers = []; for (let i = 0; i < slice.length; i++) { byteNumbers.push(slice.charCodeAt(i)); } // 8 位無符號整數值的類型化數組。內容將初始化為 0。 // 如果無法分配請求數目的字節,則將引發異常。 byteArrays.push(new Uint8Array(byteNumbers)); } let result = new Blob(byteArrays, { type: contentType }) result = Object.assign(result,{ // jartto: 這里一定要處理一下 URL.createObjectURL preview: URL.createObjectURL(result), name: `圖片示例.png` }); resolve(result) }) }
你可以這樣調用:
let base64 = base64.split(",")[1] this.base64ToBlob({b64data: base64, contentType: "image/png"}).then(res => { // 轉后后的blob對象 console.log("blob", res) })3. blob 轉 base64
blob to base64 的方法封裝
// 原理:利用fileReader的readAsDataURL,將blob轉為base64 blobToBase64(blob) { return new Promise((resolve, reject) => { const fileReader = new FileReader(); fileReader.onload = (e) => { resolve(e.target.result); }; // readAsDataURL fileReader.readAsDataURL(blob); fileReader.onerror = () => { reject(new Error("文件流異常")); }; }); }
你可以這樣調用:
this.blobToBase64(blob).then(res => { // 轉化后的base64 console.log("base64", res) })
ps: 以上方法是針對玩轉圖片流的優化,感謝原作者。
在這里貼出url轉base64, base64與blob的相互轉化的demo,其它的會更新在這里,有興趣可以戳一下這里
三、圖片處理方式的歸納 1. 后端的圖片的存儲方式在前面我們提到過,圖片在后端的存儲有兩種方式,我們回顧一下:其一:可以將圖片以獨立文件的形式存儲在服務器的指定文件夾中,再將路徑存入數據庫字段中;其二:將圖片轉換成二進制流,直接存儲到數據庫的 Image 類型字段中;
那么這兩種存儲方式,哪種更優呢?
據我了解,在互聯網環境中,大訪問量,數據庫速度和性能方面很重要。一般在數據庫存儲圖片的做法比較少,更多的是將圖片路徑存儲在數據庫中,展示圖片的時候只需要連接磁盤路徑把圖片載入進來即可。因為圖片是屬于大字段。一張圖片可能1m到幾m。這樣的大字段數據會加重數據庫的負擔,拖慢數據庫。在大并發訪問的情況下很重要。這是一個經驗。去看看dba對數據庫性能調優方面的分析都能得到這個答案的:就是圖片不要存儲在數據庫中。
因此,如果你司的后端小哥哥經常將圖片以二進制的形式存儲到數據庫然后返回給你對接,你應該知道如何去dui他了吧(滑稽臉)。
更多關于圖片或者文件在數據庫的存儲方式的歸納請戳這里
2. 前端的圖片的顯示方式對于前端來說:
圖片在前端顯示有三種方式:url、base64、blob
三種顯示方式,哪種更優雅呢?
url: 一般來說,圖片的顯示還是建議使用url的方式比較好。如果后端傳過來的字段是圖片路徑的話。
base64:如果圖片較大,圖片的色彩層次比較豐富,則不適合使用這種方式,因為其Base64編碼后的字符串非常大,會明顯增大HTML頁面,影響加載速度。
如果圖片像loading或者表格線這樣的,大小極小,但又占據了一次HTTP請求,而很多地方都會使用。則非常適用“base64:URL圖片”技術進行優化了!詳細的張鑫旭的Demo演示,請戳這里一下。
blob: 當后端返回特定的圖片二進制流的時候,就像我第一part里的情景再現說的,前端用blob容器接收。圖片用blob展示會比較好。
四、感想付出,記錄,總結。在項目中遇到的問題我都會一點一滴的記錄整理下來。我相信,這些都是一片一片散落的枝葉,隨著項目經驗的增多,這些枝葉最終一定能夠成長為一棵參天大樹。
文中的觀點受限于本人當前的技術水平,難免會有講錯的地方,歡迎評論區留言交流指正。
隨著技術水平的提升,文章會不定期的迭代而優化~你可以通過下面的方式聯系到我。
關于我我的github主頁(點擊進入)
我的掘金主頁(點擊進入)
我的SG主頁(點擊進入)
我的簡書主頁(點擊進入)
我的公眾號(點擊進入或者掃描下方二維碼)
文章回顧:
2018年的文章寫作進度表
參考資料:
ArrayBuffer對象,Blob對象
axios-api文檔
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/117431.html
摘要:對于第二種存儲方式,我們前端需要將其二進制流交由對象處理,然后通過的生成臨時賦值給屬性來顯示。當后端返回特定的圖片二進制流的時候,就像我第一里的情景再現說的,前端用容器接收。 前言 作為前端工程師 de 我們,日常少不了會跟圖片打交道。在各大電商平臺工作的前端工程師們,感受可能會更加的明顯。 以下是我之前跟圖片打交道踩到的坑,跟大家分享一下經驗。 一、情景再現 用postman請求接口...
摘要:對于第二種存儲方式,我們前端需要將其二進制流交由對象處理,然后通過的生成臨時賦值給屬性來顯示。當后端返回特定的圖片二進制流的時候,就像我第一里的情景再現說的,前端用容器接收。 前言 作為前端工程師 de 我們,日常少不了會跟圖片打交道。在各大電商平臺工作的前端工程師們,感受可能會更加的明顯。 以下是我之前跟圖片打交道踩到的坑,跟大家分享一下經驗。 一、情景再現 用postman請求接口...
摘要:前端面試每日題,以面試題來驅動學習,每天進步一點讓努力成為一種習慣,讓奮斗成為一種享受相信堅持的力量項目地址推薦歡迎跟一起折騰前端,系統整理前端知識,目前正在折騰,打算打通算法與數據結構的任督二脈。 《論語》,曾子曰:吾日三省吾身(我每天多次反省自己)。 前端面試每日3+1題,以面試題來驅動學習,每天進步一點! 讓努力成為一種習慣,讓奮斗成為一種享受!相信 堅持 的力量!!! 項目...
摘要:前端面試每日題,以面試題來驅動學習,每天進步一點讓努力成為一種習慣,讓奮斗成為一種享受相信堅持的力量項目地址推薦歡迎跟一起折騰前端,系統整理前端知識,目前正在折騰,打算打通算法與數據結構的任督二脈。 《論語》,曾子曰:吾日三省吾身(我每天多次反省自己)。 前端面試每日3+1題,以面試題來驅動學習,每天進步一點! 讓努力成為一種習慣,讓奮斗成為一種享受!相信 堅持 的力量!!! 項目...
閱讀 1916·2021-11-23 09:51
閱讀 1246·2019-08-30 15:55
閱讀 1612·2019-08-30 15:44
閱讀 758·2019-08-30 14:11
閱讀 1145·2019-08-30 14:10
閱讀 914·2019-08-30 13:52
閱讀 2629·2019-08-30 12:50
閱讀 614·2019-08-29 15:04