怎么使用Node.js的http模塊處理文件上傳?下面本篇文章就來看看在服務器端要如何處理前端上傳的文件,希望對大家有所幫助!
查看請求數據
如果我們現在向服務器發送的數據如下圖所示,里面包含了普通的字段信息 name
以及一個圖片文件 file
:
我們先來看看如何在服務器接收到文件上傳的數據,并在調試控制臺打印查看:
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 的模式來運行代碼:
點擊 "運行和調試" 后,vs code 就會幫我們把服務器運行起來了:
之后當我們發送了上傳的請求,再點擊下圖右上角的 "單步跳過",就可以看到請求的數據了 —— 那些可以被 ASCII 編譯的信息,比如英文字母,可以直接看到了,而圖片的數據則是一堆亂碼:
接下來就是處理獲取的請求數據,將里面的圖片數據截取出來然后通過寫入流生成圖片。
處理文件(圖片)數據
獲取圖片數據
因為可讀流的 '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
,得到的數據如下:
圖片的數據應該是 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),在每個表單項的開頭和結尾都有,并且在開頭處的前面都會加上兩個減號 --
,在整個表單數據結束處的末尾也會加上兩個減號。查看請求頭:
可以發現在 content-type
里定義了boundary
,于是我們可以使用如下方法獲取分隔符:
const boundary = req.headers['content-type'].split('boundary=')[1]
生成圖片
獲取到了圖片數據 imgData
后,就可以通過 fs 的 writeFile()
寫入文件生成圖片了:
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 等)打好基礎。