做者:孫輝,美團金融前端團隊成員。15年畢業加入美團,相信技術,更相信技術只是大千世界裏知識的一種,我的博客: sunyuhui.com前端
陸陸續續作了很多須要上傳圖片的項目,場景各類各樣,從先後端數據交互來看,有直接從瀏覽器裏發ajax到後端,也有用Node作中間層,在Node端轉發到後端。從用戶使用方式來看,有在移動端H5頁面獲取客戶端圖片,也有在PC端直接上傳圖片。因此打算作一個總結,梳理不一樣場景的實現思路以及遇到的問題。node
總體思路以下圖所示git
在H5頁面調用JsBridge方法,獲取圖片的Base64編碼,將base64編碼轉換成Blob二進制文件(圖中沒有標註出來),接下來在瀏覽器端構造FormData數據,最後使用Ajax發送到後端,後端返回圖片的URL。github
在實際項目中,base64編碼能夠賦值給img
標籤的src
屬性,用於預覽圖片(例子可查看FileReader對象 - MDN)。在發送給後端以前,將其轉換成Blob二進制文件,代碼以下:web
/**
* [convertToBlob 將base64轉換爲二進制文件]
* @param {[type]} base64Data [bas64文件]
* @param {[type]} type [二進制文件類型,好比: 'image/jpg']
* @return {[type]} [二進制文件]
*/
function convertToBlob(base64Data, type) {
//去掉base64中的換行符,webkit會自動去除,可是IOS9以及IOS8中不會自動去除,致使轉換出錯
base64Data = base64Data.replace(/\s/g, '');
var text = window.atob(base64Data.split(",")[1]);
var buffer = new ArrayBuffer(text.length);
var ubuffer = new Uint8Array(buffer);
for (var i = 0; i < text.length; i++) {
ubuffer[i] = text.charCodeAt(i);
}
var Builder = window.WebKitBlobBuilder || window.MozBlobBuilder;
var blob;
if (Builder) {
var builder = new Builder();
builder.append(buffer);
blob = builder.getBlob(type);
} else {
blob = new window.Blob([buffer], {
type: type
});
}
return blob;
}複製代碼
PC和H5頁面惟一一個不一樣點在於獲取圖片數據的方式不一樣。H5經過JsBridge方法直接獲取圖片的Base64編碼,而PC端須要咱們本身去讀取。ajax
經過input:file
標籤獲取File對象,使用FileReader對象的readAsDataURL方法 - MDN讀取File獲得Base64編碼,將Base64編碼轉換成Blob二進制文件,最後構造FormData數據。後端
經過上面兩種場景,咱們基本能總結出上傳圖片的思路。瀏覽器
若是以爲很差理解的話,建議先去MDN瞭解下各個數據類型(File, Blob)的含義,以及和JavaScript中原生數據類型的區別。bash
出於嚐鮮的心理,在最近的一個項目中,我使用了Node層轉發的方式來處理圖片。沿用前面總結的思路,咱們須要獲取到圖片內容,構造FromData數據,app
Node層怎麼獲取到圖片內容呢?,Node層怎麼構造FormData數據呢?
咱們使用了formidable來接收瀏覽器端發送的FormData數據,formidable很是好的一點是將文件內容和其餘參數分開了,方便咱們獲取
request有一個 advanced 用法是在使用post方法上傳數據時,能構造FormData數據,
完整代碼:
var form = new formidable.IncomingForm();
form.parse(this.req, function(err, fileds, files) {
// fileds:和文件一塊兒上傳的參數
// files: 文件,File類型
if(err) {
return console.log('param error', err);
}
var filePath = files[0].path;
var fileName = files[0].name;
var r = request.post('uploadImageUrl', function(err, httpResponse, body) {
if(err) {
console.log(err);
}
body = JSON.parse(body);
console.log(body) //返回數據
})
var form = r.form();
//和文件一塊兒上傳的其餘參數
form.append('param', fileds.param);
//讀取文件流
form.append('multipartFile', require('fs').createReadStream(filePath), {
filename: fileName
});
});複製代碼
固然在Node層構造FormData還有其餘方式,好比:form-data。
有一個須要注意的地方,在Node層,是無法像瀏覽器端那樣將Base64編碼轉換成Blob二進制文件的方法的,咱們獲取二進制文件內容的方式,是經過createReadStream
建立一個讀取的數據流。
ok,總結來看,不論是在瀏覽器端仍是在Node層,咱們的最終目的都是要獲取圖片的二進制文件,而後構造FormData數據,只是在不一樣環境中,獲取二進制文件的方式不一樣。
但願對你們有幫助 ~
最後,團隊爲了招聘方便,整了個公衆號,主要是一些招聘信息,團隊信息,全部的技術文章在公衆號裏也能夠看到,對了,若是你想去美團其餘團隊,咱們也能夠幫你內推哦 ~