闲话图片上传

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

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

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

整体思路如下图所示



在H5页面调用JsBridge方法,获取图片的Base64编码,将base64编码转换成Blob二进制文件(图中没有标注出来),接下来在浏览器端构造FormData数据,最后使用Ajax发送到后端,后端返回图片的URL。

在实际项目中,base64编码可以赋值给img标签的src属性,用于预览图片(例子可查看FileReader对象 - MDN)。在发送给后端之前,将其转换成Blob二进制文件,代码如下:

/**
 * [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端需要我们自己去读取。



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

通过上面两种场景,我们基本能总结出上传图片的思路。



如果觉得不好理解的话,建议先去MDN了解下各个数据类型(File, Blob)的含义,以及和JavaScript中原生数据类型的区别。

Node层转发

出于尝鲜的心理,在最近的一个项目中,我使用了Node层转发的方式来处理图片。沿用前面总结的思路,我们需要获取到图片内容,构造FromData数据

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数据,只是在不同环境中,获取二进制文件的方式不同。

希望对大家有帮助 ~

最后,团队为了招聘方便,整了个公众号,主要是一些招聘信息,团队信息,所有的技术文章在公众号里也可以看到,对了,如果你想去美团其他团队,我们也可以帮你内推哦 ~

二维码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值