闲话图片上传

做者:孙辉,美团金融前端团队成员。15年毕业加入美团,相信技术,更相信技术只是大千世界里知识的一种,我的博客: sunyuhui.com前端

陆陆续续作了很多须要上传图片的项目,场景各类各样,从先后端数据交互来看,有直接从浏览器里发ajax到后端,也有用Node作中间层,在Node端转发到后端。从用户使用方式来看,有在移动端H5页面获取客户端图片,也有在PC端直接上传图片。因此打算作一个总结,梳理不一样场景的实现思路以及遇到的问题。node

H5页面使用Ajax直接发送到后端

总体思路以下图所示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页面使用Ajax直接发送到后端

PC和H5页面惟一一个不一样点在于获取图片数据的方式不一样。H5经过JsBridge方法直接获取图片的Base64编码,而PC端须要咱们本身去读取。ajax



经过input:file标签获取File对象,使用FileReader对象的readAsDataURL方法 - MDN读取File获得Base64编码,将Base64编码转换成Blob二进制文件,最后构造FormData数据。后端

经过上面两种场景,咱们基本能总结出上传图片的思路。浏览器



若是以为很差理解的话,建议先去MDN了解下各个数据类型(File, Blob)的含义,以及和JavaScript中原生数据类型的区别。bash

Node层转发

出于尝鲜的心理,在最近的一个项目中,我使用了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数据,只是在不一样环境中,获取二进制文件的方式不一样。

但愿对你们有帮助 ~

最后,团队为了招聘方便,整了个公众号,主要是一些招聘信息,团队信息,全部的技术文章在公众号里也能够看到,对了,若是你想去美团其余团队,咱们也能够帮你内推哦 ~

二维码
二维码
相关文章
相关标签/搜索