《上傳那些事兒之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的配置參數,進行地址轉存 。

推薦閱讀