浅析Node中http模块怎么处理文件上传
怎么使用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 等)打好基础。
以上就是浅析Node中http模块怎么处理文件上传的详细内容,更多请关注其它相关文章!