《上传那些事儿之Nest与Koa》——文件格式怎么了!

转载自:juejin - 马睿不想说话
概要本文主要针对在使用node作为服务端接口时,前端上传上传文件至node作为中转,再次上传至oss/cdn的场景 。以及针对在这个过程中,需要对同一个文件进行不同形式之间转换的问题 。
Blob、File、Buffer与stream在解答上述问题之前,我们要先了解一下Blob、File、Buffer与stream这四者分别是什么 。以及这四者的关系是什么样的 。
Blob

Blob 对象表示一个不可变、原始数据的类文件对象 。
这是MDN对Blob的说明 。简而言之 , 所有的“数据”都可以用blob的格式进行存储 , 而且不一定是 JavaScript 原生格式的数据 。包括但不仅限于文本、二进制、文档流等 。而通过Blob的实例方法(Blob.prototype.arrayBuffer()Blob.prototype.stream()),我们还可以将blob转换为Buffer和ReadableStream 。
FileFile接口基于 Blob,继承了 blob 的功能并将其扩展以支持用户系统上的文件 。接口提供有关文件的信息,并允许网页中的 JavaScript 访问其内容,且可以用在任意的 Blob 类型的 context 中 。需要注意的一点是,File并没有任何定义方法,而是只从Blob继承了slice方法 。
BufferBuffer是数据以二进制形式临时存放在内存中的物理映射 。在Nodejs中,Buffer类是用于直接处理二进制数据的全局类型 。它可以以多种方式构建 。
streamNode.js 中有四种基本的流类型:
  • Writable: 可以写入数据的流(例如, fs.createWriteStream()) 。
  • Readable:可以从中读取数据的流(例如, fs.createReadStream()) 。
  • Duplex: 两者都是Readable和的流Writable(例如, net.Socket) 。
  • TransformDuplex可以在写入和读取数据时修改或转换数据的流(例如,zlib.createDeflate()) 。
开发前的规划在我们进行文件上传的过程中,经历了两个阶段:
  1. 获取前端上传的文件
  2. 处理文件后,调用内部服务上传至cdn
其实这样看来的话,这是很简单的两个阶段,我们只需要拿到前端的文件后传递给另外一个接口就可以了,可是在这个过程中,有几个我们不得忽视的问题:
  1. 我们的node服务中获取到的前端上传的文件到底是什么格式?
  2. 我们进行上传oss/cdn的接口,需要我们上传的文件格式又是什么样的?
  3. 文件名称如何保持不变/如何进行混淆?
  4. 如何完成文件格式的校验或过滤?
只有在考虑清楚了以上这些内容的处理之后,才应该来考虑我们接口本身的业务逻辑的完善与开发 。
开发中的问题由于一些内部原因,Node端的开发经历了从koa2到express的重构 。所以针对两个框架的文件处理,我也都有幸(bushi)全都经历了一次 。
node上传格式由于上传至oss的第三方接口可以在前端调用,也可以在node中进行调用,所以在Postman中可以模仿上传过程 , 由此可以看到第三方接口真正需要我们传入的其实是一个ReadStream格式的文件 。所以我们的目标也很简单 , 那就是无论我们获取到什么格式的文件,都转换成为ReadStream格式即可 。
《上传那些事儿之Nest与Koa》——文件格式怎么了!

文章插图
koa2不同于在koa中使用koa-bodyparser模块来完成post请求的处理;在koa2中,使用koa-body模块不仅可以完成对于post请求的处理,同时也能够处理文件类型的上传 。
在这种情况下我们只需要通过ctx.request.files即可访问前端上传给我们的文件实例,同时我们可以看到我们获取到的是一个WriteStream格式的文件 。通过size、name、type等属性 , 即可获取相应的属性,用于进行文件格式的校验与判断 。
当我直接使用fs.createReadStream方法将它转换为我们所需要的格式时,问题也随之而来:由于上传后的文件经过了koa的处理,所以我们得到的WriteStream的path发生了一些变化,他变成了内存中的一个地址导致我们转化之后的文件名称也发生了变化,变成了一个内存中的地址串 。
很显然,这是我们不想要看到的,因为这对于我们来说是不可控的 。为了解决这个问题,我尝试了两种解决方式均有效,大家可以自行选择 。
【《上传那些事儿之Nest与Koa》——文件格式怎么了!】1. 使用koa-body的配置参数,进行地址转存 。

推荐阅读