100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > 关于使用 Connect-Busboy 实现文件上传 优化说明

关于使用 Connect-Busboy 实现文件上传 优化说明

时间:2020-12-29 07:12:52

相关推荐

关于使用 Connect-Busboy 实现文件上传 优化说明

这篇博文完全上关于上一篇的优化 先看上一篇 node.js 在 Express4.0 框架使用 Connect-Busboy 实现文件上传 因为从上次博客改用 connect-busboy 来上传文件后,发现了明显的一个bug

bug 说明

文件显示上传 100% ,然后预览的时候,偶尔会发现图片只能显示一部分 这种情况在 png 格式 图片尤其严重 昨天重新 review 代码,发现一个bug ,当然和 connect-busboy 一点关系都没有,而是涉及到流的处理过程.

这里把上一篇 blog 里贴出的上传代码在放上来分析一下

function upload(req, res, next) {req.busboy.on('file', function (fieldname, file, filename, encoding, mimetype) {var tmp_path=path.join(os.tmpDir(), path.basename(filename));file.pipe(fs.createWriteStream(tmp_path));file.on('end',function(){var uuid = tool.generateUUID();commfile.savePathFile(uuid, mimetype, tmp_path, true, function(err, fileBase64) {if (err) {res.json({success:false,url:''});}else{res.json({success: true,url: '/file/' + uuid});}});});});req.pipe(req.busboy);}

针对代码,我们细致理一下req.busboy.on('file' ,function(......).....)

1 .req.busboy.on 方法用来监听 form 提交的参数的事件,其中 on(‘file’ ) 是监听 form 提交二进制文件流事件. 上面的监听事件的回调函数传递过来几个参数,我们重点看下 file 参数 file 是二进制文件流句柄,它是一个标准的 stream 2 .接着我取到服务器临时文件目录 ,和 文件名,组合成一个文件路径

类似这样的路径: /Users/zhangzhi/data/temp/aaa.pngvar tmp_path=path.join(os.tmpDir(), path.basename(filename));3 .接着我把 file 流写入上面定义的文件路径file.pipe(fs.createWriteStream(tmp_path));

这里出现了一个流程冗余问题

上面用到了 pipe 希望读一下我的另外一篇文章了解 pipe 原理 node.js 在io实现异步非阻塞

然后我读取刚才的临时文件到字节数组,转化为 base64 字符串,存储在了LevelDB数据库file.on('end' ....)
bug 就出现在这里

我们回头分析一下上面出现的流程冗余问题及bug

流程冗余

假如我的图片是直接保存在服务器的某个文件夹下面,那么上面的 1,2,3 流程是没有问题,(当然不需要临时文件目录,直接写入到服务器指定的保存图片目录即可) 但是我目前的博客图片全部在 levelDB 数据库里,所以没有必要先在临时目录生成图片,然后读取图片字节数组,再转化为base64串写入数据库 中间的弯路就是保存临时文件再读取

我们已经拿到了 file 上传文件流句柄,所以完全可以直接塞到二进制数组中,临时保存,毕竟不是上面巨大文件,对内存容忍度为0 ,如下代码

var dataArr = [];file.on("data", function (chunk){dataArr.push(chunk);});

上面我们监听 file 的 data 事件,通过源源不断的字节流传输到服务器,我们就不管三七二十一先塞进 dataArr 二进制数组中 那么接着我们要做什么,我们直接可以把上面的 dataArr 数据转化成一个 base64 字符串存入数据库,具体的代码实现在下面,我们该分析下上面的bug了

bug出现

我们上面说到了第 4 步有一个隐形的bug ,在上传文件的时候偶尔出现,尤其是 png 图片时,100% 暴露,叔能忍,婶婶也忍不了啊… 为什么第 4 步这里有bug ? 还是脱离不了整个流程,简单回顾下.

上传的文件流 file 写入到临时文件目录中 ,假设这个过程叫 A 我们读取 临时文件 文件转化为 base64 字符串, 这个过程叫 B 我们应该什么时候去读取 临时文件,应该在 A 过程全部结束, 而 A 过程结束是指 file 上传文件流全部传完 并且 文件流全部写入到了临时文件 但是我们上面 监听的 file.on('end’,function(){…} 只是监听上传文件流结束的事件,具体这个文件流是否完全写入到临时文件,根本不知道,但是这时我们已经做了一个错误的决定,就是开始读取 临时文件 转化为base64 字符串 所以: 当文件流仅仅是通过 http 传完时,但是并没有写完到临时文件,这是我们立即读取图片,一定是不完整的图片

如果这里一定要这样去做,改如果修改一下代码呢:

function upload(req, res, next) {req.busboy.on('file', function (fieldname, file, filename, encoding, mimetype) {var tmp_path=path.join(os.tmpDir(), path.basename(filename));var passedLength = 0;var writeStream = fs.createWriteStream(tmp_path);file.on('data',function(trunk){passedLength += chunk.length;if (writeStream.write(chunk) === false) {file.pause();}});file.on('end',function(){//当没有数据读取,关闭写入数据流writeStream.end();});writeStream.on('drain', function() {//速度写入完毕后//这里我们才去执行把图片文件转换成 base64 字符串写入数据库操作var uuid = tool.generateUUID();commfile.savePathFile(uuid, mimetype, tmp_path, true, function(err, fileBase64) {if (err) {res.json({success:false,url:''});}else{res.json({success: true,url: '/file/' + uuid});}});});req.pipe(req.busboy);}

上面的代码是没有经过测试的,直接敲上去,只是为了说明按照原来流程的正确处理方式

流程问题理清了,bug 也找到了.下面做如下修复

先上代码

req.busboy.on('file', function (fieldname, file, filename, encoding, mimetype) {var dataArr = [], len = 0,strBase64;file.on("data", function (chunk){dataArr.push(chunk);len += chunk.length;});file.on("end", function () {strBase64 = Buffer.concat( dataArr, len ).toString('base64');var uuid=tool.generateUUID();commfile.saveFile(uuid,mimetype,strBase64,function(err){if (err) {res.json({success:false,url:''});}else{res.json({success: true,url: '/file/' + uuid});}})});});req.pipe(req.busboy);

简单说明一下上面的代码 file.on(“data” 事件实时把字节流写入数组中 file.on(“end” 当上传文件字节流结束后, 把字节数组转化为 base64 字符串 strBase64 = Buffer.concat( dataArr, len ).toString(‘base64’); 最后我们把 base64 字符串写入数据库 这样上传图片再也不会出现写入数据库的图片不完整的bug 了.

出自:关于使用 Connect-Busboy 实现文件上传 优化说明

你可能感兴趣

pandoc markdown 生成pdf文档forever node.js web应用中不可或缺的伟大模块node.js AES/ECB/PKCS5Padding 与其他语言的加密解密通用ejs母版页让你的node.js应用开发更快更有效- 一介布衣node.js 实现一个简单的登录拦截器

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。