前端上傳圖片

前端上傳圖片到服務器,通常會有兩種方式:前端

1. Base64編碼nginx

2. FormData文件流canvas

首先,若是圖片轉爲 Base64 後,除了體積會增大33%左右外,更大的問題是,你覺得你是在以字符串的格式傳輸二進制。 其實非也,尤爲是你把它轉爲 JSON 傳給後端,因爲變成了須要解析的字符串,對後端的壓力會陡增,你會明顯看處處理速度的急劇下滑。以及,你還須要去調 nginx 配置文件以免 nginx 以爲你字符串過長,直接報錯 Entity Too Large 把包拒掉。後端

因此,Base64 更適合用來處理小圖,好比頭像或小圖標之類,保存在本地,以減小 Http 的請求次數;而大圖比較適合用 FormData 文件流來傳輸。服務器


而我最近的需求是把手機拍照的圖片上傳到服務器,因此肯定了用文件流來處理。app

而咱們的應用是通過 Hbuilder 打包後的 Web App, 加持了 iOS 和 Android 的原生 SDK 的功能,因此面臨着兩個選擇:函數

  1. 使用 Web 原生的 <input> 來拍照及選取相冊
  2. 使用 Hbuilder 的提供的 SDK

若是用原生 <input> ,能夠這麼寫(項目用的是 Vue):ui

<input type="file" accept="image/*" capture="camera" @change="onChange" multiple>編碼

實際上呢,坑還很多。。。code

加上capture="camera"這個屬性,是爲了讓手機可選相機,不過真實狀況是:

  • 部分 Android 手機上調用不了相機,始終只能選相冊;(解決辦法:請教 Android 原生開發的童鞋吧)

  • 蘋果手機上,只能拍照,不能選相冊;(解決辦法:判斷 iOS,若是是 iOS 就去掉 capture 屬性)

因此, Android 不能調用相機這點,就把 Web 原生的方案斃掉了,後來轉用 HBuilder 的 SDK;


接下來的大體思路:

  1. 獲取到 File 對象

  2. FileReader 轉成 dataUrl

  3. canvas 接收 dataUrl

  4. 對圖片進行寬高比的設置(壓縮大小)

  5. canvas.toDataURL 將壓縮後的圖片生成新的 Base64 編碼

  6. 執行回調函數,將新的 Base64 轉換爲文件

  7. 最後拿到文件,構造 FormData 對象上傳至服務器。

特別要注意的是:

  • FormData 的請求方式,每一個參數都須要經過 append 方法添加進去;

  • 不須要單獨設置請求頭的 Content-Type,系統自動會設定爲 multipart/form-data


通過幾天線上的驗證,事實證實,只用文件流傳圖片,有時也會報 Entity too large 這個錯誤,後來通過定位發如今 canvas.toDataURL 時,最好用 jpeg 格式進行壓縮,不要用 png 的無損壓縮,這點很是關鍵!

---The End

相關文章
相關標籤/搜索