淺析Node中http模組怎麼處理檔案上傳

2023-03-09 22:00:34

怎麼使用Node.js的http模組處理檔案上傳?下面本篇文章就來看看在伺服器端要如何處理前端上傳的檔案,希望對大家有所幫助!

檢視請求資料

如果我們現在向伺服器傳送的資料如下圖所示,裡面包含了普通的欄位資訊 name 以及一個圖片檔案 file

1.png

我們先來看看如何在伺服器接收到檔案上傳的資料,並在偵錯控制檯列印檢視:

const http = require('http')
const server = http.createServer((req, res) => {
  req.setEncoding('binary')
  req.on('data', data => {
    console.log(data)
  })
  req.on('end', () => {
    console.log('上傳結束')
    res.end('上傳成功')
  })
})
server.listen(3010, () => console.log('伺服器開啟'))
登入後複製

想要能看懂列印的結果,我們通過 req.setEncoding('binary') 設定了字元編碼為 'binary',這樣得到的資料就不是 buffer 物件而是 ASCII 編碼後的字串,我們就可以使用一些字串的方法來處理資料了。

但是當檔案大小比較大時,直接通過在命令列輸入 node 或 nodemon 來執行程式碼,得到的資料無法完全在控制檯展示。所以我們可以在要列印請求資料的地方打上斷點,通過 debugger 的模式來執行程式碼:

2.png

點選 "執行和偵錯" 後,vs code 就會幫我們把伺服器執行起來了:

3.png

之後當我們傳送了上傳的請求,再點選下圖右上角的 "單步跳過",就可以看到請求的資料了 —— 那些可以被 ASCII 編譯的資訊,比如英文字母,可以直接看到了,而圖片的資料則是一堆亂碼:

4.png

接下來就是處理獲取的請求資料,將裡面的圖片資料擷取出來然後通過寫入流生成圖片。

處理檔案(圖片)資料

獲取圖片資料

因為可讀流'data' 事件一次最多讀取 64kb 的資料,當圖片比較大時,可能會觸發多次,所以我們定義變數 reqData 來儲存請求發來的資料:

let reqData = ''
req.on('data', data => {
  reqData += data
})
req.on('end', () => {
  console.log(reqData) // 在這行打斷點
  res.end('上傳成功')
})
登入後複製

req 觸發了 'end' 事件說明請求資料讀取完畢,如果在上列程式碼的第 6 行 console.log(reqData) 處打個斷點,然後檢視 reqData,得到的資料如下:

5.png

圖片的資料應該是 image/png\r\n\r\n\r\n----------------------------158329774739626517859573--\r\n 中間這段。我們可以去獲取圖片資料的起(imgDataStartIndex)止(imgDataEndIndex)位置的 index,然後使用 substring() 做個擷取,最後再使用 trim() 方法去除首位的空格 \r\n

const imgType = 'image/png'
const imgDataStartIndex = reqData.indexOf(imgType) + imgType.length
const imgDataEndIndex = reqData.indexOf(`--${boundary}--`)
const imgData = reqData.substring(imgDataStartIndex, imgDataEndIndex).trim()
登入後複製

獲取分隔符 boundary

--------------------------158329774739626517859573是使用者端隨機生成的,用於分割表單裡的每段資料的分隔符(boundary),在每個表單項的開頭和結尾都有,並且在開頭處的前面都會加上兩個減號 --,在整個表單資料結束處的末尾也會加上兩個減號。檢視請求頭:

6.png

可以發現在 content-type 裡定義了boundary,於是我們可以使用如下方法獲取分隔符:

const boundary = req.headers['content-type'].split('boundary=')[1]
登入後複製

生成圖片

獲取到了圖片資料 imgData 後,就可以通過 fswriteFile() 寫入檔案生成圖片了:

fs.writeFile('./img.png', imgData, 'binary', err => {
  if (!err) console.log('圖片寫入成功')
})
登入後複製

注意需要在第三個引數傳入'binary' 來設定 encoding

總結

現將程式碼彙總如下:

const http = require('http')
const fs = require('fs')

const server = http.createServer((req, res) => {
  req.setEncoding('binary')
  const boundary = req.headers['content-type'].split('boundary=')[1]
  let reqData = ''
  req.on('data', data => {
    reqData += data
  })
  req.on('end', () => {
    const imgType = 'image/png'
    const imgDataStartIndex = reqData.indexOf(imgType) + imgType.length
    const imgDataEndIndex = reqData.indexOf(`--${boundary}--`)
    const imgData = reqData.substring(imgDataStartIndex, imgDataEndIndex).trim()
    fs.writeFile('./img.png', imgData, 'binary', err => {
      if (!err) console.log('圖片寫入成功')
    })
    res.end('上傳成功')
  })
})

server.listen(3010, () => console.log('伺服器開啟'))
登入後複製

上述程式碼能夠成功執行還有一些限制,比如只能處理單檔案上傳,且檔案需要是 png 格式的圖片,並且放在表單最後一項。文章的目的在於簡單瞭解使用 node 的 http 模組搭建的伺服器大體上是如何處理上傳檔案的請求的,為將來深入學習其它基於 http 模組的框架(express.js、koa.js 等)打好基礎。

更多node相關知識,請存取:!

以上就是淺析Node中http模組怎麼處理檔案上傳的詳細內容,更多請關注TW511.COM其它相關文章!