用Node-HTTP模块实现文件上传

前言


🫥需求:这个需要上传一个文件,后端你支持一下吧!听到这句话心里很自然的反应就是,服务端逻辑关我前端什么事,醒一醒,你现在是服务端开发了,快用Node把基本的功能开发下试试看,我们知道文件上传的功能对于前端来说就是一个基本的formadata进行表单提交的需求,很容易就实现了,但是对于服务端来讲就不仅仅是这个样子了,无论是什么技术栈,在进行文件上传的功能开发的时候大部分时候都是使用插件,但是既然我们刚学习完HTTP模块,那么就是使用这个模块来手写一个简单的demo版本的文件上传吧,既能巩固下HTTP模块的使用,还能理解文件上传的底层处理方式。

一.文件上传的错误❌方式


👹首先我们按照我们正常的思维方式来搭建一个HTTP服务,然后获取客户端的数据打印,看是否能够接受到客户端上传的二进制的buffer数据,然后创建可写流来进行写入。

js 复制代码
const http = require("http")
const fs = require("fs")
const server = http.createServer((req, res) => {
  // 客户端上传的数据是表单数据
  const writeStream = fs.createWriteStream('./picture.png', {
    flags: 'a+'
  })
  req.on('data', (data) => {
    writeStream.write(data)
  })
  req.on('end', () => {
    res.end("文件上传成功")
  })
})
server.listen(8000, () => {
  console.log("服务启动在8000端口")
})

🫥我们通过apifox来模拟客户端发送一个请求,来上传一张图片

🤡点击请求,我们可以看到服务端终端打印文件上传成功的字样。

🥺然后我们就会看到成功生成了一张图片,到那时当我们点击它的时候这个图片是打不开的

错误内容如下:

🤡没错,这样的上传方式是错误的,但是上传的整体流程是正确的,文件上传的整体流程是:

  1. 客户端通过将input的类型设置为file来上传文件,上传的方式是通过formdata的方式。
  2. 服务端搭建一个服务,获取客户端发送的请求,拿到对应的二进制buffer内容。
  3. 然后将这个二进制buffer的内容创建可写流进行写入,生成一张一模一样的图片。
  4. 然后触发结束回调,显示文件上传成功。

🥱那么错误究竟在什么地方哪?先别急,我们既然是学习就慢慢来,我们先对上述错误的代码进行优化,其实req对象是一个可读流,既然是读取--->写入那么我们就可以使用pip(见Node-Stream)的方式直接一把梭哈。

js 复制代码
const http = require("http")
const fs = require("fs")
const server = http.createServer((req, res) => {
  // 客户端上传的数据是表单数据
  const writeStream = fs.createWriteStream('./picture.png', {
    flags: 'a+'
  })
  req.pipe(writeStream) // 直接通过管道进行写入
})
server.listen(8000, () => {
  console.log("服务启动在8000端口")
})

🦝接下来我们来排查错误,首先我们直接查看buffer是看不懂的,因为buffer全部是基于binary展示的进制,为了能够看懂我们使用req.setEncoding('binary')来设置一下编码方式,更改之后的代码如下

js 复制代码
const http = require("http")
const fs = require("fs")
const server = http.createServer((req, res) => {
  req.setEncoding('binary') // 设置为二进制

  req.on('data', (data) => {
    console.log(data)
  })
  req.on('end', () => {
    res.end("文件上传成功")
  })
})
server.listen(8000, () => {
  console.log("服务启动在8000端口")
})

终端控制台打印的内容,后半部分内容如下:

首部内容如下,我们可以通过联系在一起看来我们会发现,其中有很多比较杂乱的内容,这些内容是相对于图片本身来讲多余的部分,例如下方的form-data的内容很明显是HTTP头部的信息内容,所以导致文件打开的原因就是图片文件二机制数据中混入了其他数据。

二.文件上传正确的✅处理方式


🤡通过上述的分析,我们看到了造成错误的原因是混入的多余数据,那么为了能让图片的数据正常,我们首先需要对文本进行处理,我们的处理过程如下:

js 复制代码
const http = require("http")
const fs = require("fs")
const server = http.createServer((req, res) => {
  req.setEncoding('binary') // 设置为二进制
  let formdata = '' // 用来存储数据
  req.on('data', (data) => {
    formdata += data
    // 截取从image/jpeg之后的所有字符串
    const imgType = 'image/jpeg'
    const imgTypePosition = formdata.indexOf(imgType) + imgType.length // 获取对用索引
    let imgData = formdata.substring(imgTypePosition) // 从此位置一直截取到最后
    // imgData开始位置会有两个空格,使用正则去除空格
    imgData = imgData.replace(/^\s\s*/, '')
    // 替换最后的boundary
    const regex = /--(.+?)--/ // 使用捕获组
    const match = imgData.match(regex)
    let boundary = match[1]
    imgData = imgData.substring(0, imgData.indexOf(`--${boundary}--`))
    // 将处理过的数据进行写入
    fs.writeFile('./picture.png', imgData, 'binary', () => {
      console.log("文件存储成功")
      res.end("文件上传成功~")
    })
  })
  req.on('end', () => {
    res.end("文件上传成功")
  })
})
server.listen(8000, () => {
  console.log("服务启动在8000端口")
})

然后我们在客户端进行上传图片,终端显示文件上传成功。

接下来我们打开我们的图片,看是否能够正常展示,说明文件上传处理成功了。

三.总结


🤗我们在上述通过HTTP模块实现了一个简单流程的文件上传,到那时我们发现,直接上传我们并不能查看图片,是因为图片文件写入了很多多余数据,如果想处理一下我们需要进行对数据进行处理,通过正则匹配,来删除多余的部分,当正确获取数据流之后将这些内容写入就能正常得到上传的图片了。

相关推荐
wn53139 分钟前
【Go - 类型断言】
服务器·开发语言·后端·golang
希冀1231 小时前
【操作系统】1.2操作系统的发展与分类
后端
GoppViper2 小时前
golang学习笔记29——golang 中如何将 GitHub 最新提交的版本设置为 v1.0.0
笔记·git·后端·学习·golang·github·源代码管理
爱上语文3 小时前
Springboot的三层架构
java·开发语言·spring boot·后端·spring
serve the people3 小时前
springboot 单独新建一个文件实时写数据,当文件大于100M时按照日期时间做文件名进行归档
java·spring boot·后端
罗政8 小时前
[附源码]超简洁个人博客网站搭建+SpringBoot+Vue前后端分离
vue.js·spring boot·后端
拾光师10 小时前
spring获取当前request
java·后端·spring
Java小白笔记11 小时前
关于使用Mybatis-Plus 自动填充功能失效问题
spring boot·后端·mybatis
JOJO___13 小时前
Spring IoC 配置类 总结
java·后端·spring·java-ee
白总Server14 小时前
MySQL在大数据场景应用
大数据·开发语言·数据库·后端·mysql·golang·php