资讯专栏INFORMATION COLUMN

用Node处理文件上传

HtmlCssJs / 2944人阅读

摘要:前言在开发中,文件上传是一个非常常见非常重要的功能。本文将介绍如何用处理上传的文件。前端界面如下用户从浏览器中选择文件,点击上传,将发起请求到服务器,服务器将接受到的文件存储在服务器硬盘中。

前言

在Web开发中,文件上传是一个非常常见、非常重要的功能。本文将介绍如何用Node处理上传的文件。

需求分析

由于现在前后端分离很流行,那么本文也直接采用前后端分离的做法。前端界面如下:

用户从浏览器中选择文件,点击上传,将发起http请求到服务器,服务器将接受到的文件存储在服务器硬盘中。

前端部分

ajax请求库采用axios,为了简化说明,前端限制上传的文件类型只能为图片,且一次只能上传一张,有兴趣的朋友可以自行补充,代码如下:




  
  Title
  


  
  

  

后端部分

这是本文要介绍的重点,为了用高效流畅的方式来解析文件上传请求,我们先引入formidable库:

npm install formidable --save

formidable的流式解析器让它成为了处理文件上传的绝佳选择,也就是说它能随着数据块的上传接收它们,解析它们,并吐出特定的部分,相信熟悉流的朋友会很好理解。这种方式不仅快,还不会因为需要大量缓冲而导致内存膨胀,即便像视频这种大型文件,也不会把进程压垮。
首先,我们在根目录下创建myImage文件,用于存放上传的图片(注意:如果没有创建,会导致上传报错),接着,我们创建一个IncomingForm实例form,并且设置存放路径为myImage文件夹。代码如下:

var http = require("http")
var formidable = require("formidable")

var server = http.createServer(function(req, res){
  // 1 设置cors跨域
  res.setHeader("Access-Control-Allow-Origin", "*")
  res.setHeader("Access-Control-Allow-Headers", "Content-Type")
  res.setHeader("Content-Type", "application/json")

  // 2
  switch (req.method) {
    case "OPTIONS":
      res.statusCode = 200
      res.end()
      break
    case "POST":
      upload(req, res)
      break
  }
})

function upload(req, res) {
  // 1 判断
  if (!isFormData(req)) {
    res.statusCode = 400
    res.end("错误的请求, 请用multipart/form-data格式")
    return
  }

  // 2 处理
  var form = new formidable.IncomingForm()
  form.uploadDir = "./myImage"
  form.keepExtensions = true

  form.on("field", (field, value) => {
    console.log(field)
    console.log(value)
  })
  form.on("end", () => {
    res.end("上传完成!")
  })

  form.parse(req)
}

function isFormData(req) {
  let type = req.headers["content-type"] || ""
  return type.includes("multipart/form-data")
}

server.listen(3000)
console.log("port is on 3000.")

node app开启http服务器后,在前端页面中上传一张kitty.jpg,我们看到控制台打印出了前端上传的imgName属性:kitty.jpg

并且,myImage文件夹目录下多了一张图片:

打开一看,正是从前端上传的那张kitty.jpg

文件改名

我们发现,这个默认的文件名称并不是我们想要的,我们想改成以当前时间戳命名的文件,添加的功能代码如下:

  var fs = require("fs")

  form.on("file", (name, file) => {
    // 重命名文件
    let types = file.name.split(".")
    let suffix = types[types.length - 1]
    fs.renameSync(file.path, "./myImage/" + new Date().getTime() + "." + suffix)
  })

再次上传,发现现在存的照片名称已经变成我们想要的格式了。

添加上传进度

Formidable的progress事件能给出收到的字节数,以及期望收到的字节数。我们可以借助这个做出一个进度条。
我们为上面的程序添加下面的代码,每次有progress事件激发,就会计算百分比并用console.log()输出:

  form.on("progress", (bytesReceived, bytesExpected) => {
    var percent = Math.floor(bytesReceived / bytesExpected * 100)
    console.log(percent)
  })

再次上传一张图片,现在控制台已经会打印出进度显示了:

当然,一般情况下,我们是要把这个进度传回到用户的浏览器中去,这对于任何想要上传大型文件的程序来说是个很棒的特性,并且这是个很适合用Node完成的任务。比如说用WebSocket协议,或者像Socket.IO这样的实时模块,关于Node中使用websocket,后面我会多带带出一篇文章来介绍。

错误处理

任何时候都不要忘了对程序添加错误处理,如果你的程序在重要的时候崩掉了,可能轻则被老板打屁股,重则拉出去祭天。想象一下,如果用户上传的图片很大,并且用户的网络还很慢,那么上传的时间会超出前端代码中设置的请求超时时间2s,服务器就会崩掉,不信?我们来试一下。
首先,我选择了一张很大的图片,5M,并且用chrome浏览器将浏览器网络环境设置为slow 3g,设置方法如下:
f12打开开发者工具,在more tools--network conditions

点击上传,我们看见服务端控制台的信息如下,服务器崩掉了:

所以,最后我们加上了错误处理,代码如下:

  // 加上错误处理,防止用户网络慢,或者取消上传,导致服务器崩掉
  form.on("error", err => {
    console.log(err)
    res.statusCode = 500
    res.end("服务器内部错误!")
  })
小结

现在,相信你已经学会了如何用Node处理文件上传了,结合前面的那篇用Node提供静态文件服务的文章,你是不是能够自己摸索着去尝试做一些有趣的事情了呢?

参考阅读

formidable文档
input的file类型的accept属性

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/95986.html

相关文章

  • node 学习笔记(3)--Express

    摘要:执行安装依赖项,然后执行启动程序。模板的内容保存在内存中,性能会得到显著提升。视图查找当或被调用时,会先检查是否有文件在这个绝对路径上。代码清单修改了之前的实现,给出照片被上传时提供的名称,比如 Express起步 安装ExpressshowImg(https://segmentfault.com/img/bVXsFT?w=800&h=44); 一个最小的Express 程序showI...

    lewif 评论0 收藏0
  • 基于Node的React图片上传组件实现

    摘要:常用的设置如下下的请求风格下的请求和不太一样,在正式的请求发出之前都会先发一个类型为的请求作为试探,只有当该请求通过以后,正式的请求才能发向服务端。所以服务端路由我们还需要处理这样一个请求注意该请求同样需要设置跨域。 写在前面 红旗不倒,誓把JavaScript进行到底!今天介绍我的开源项目 Royal 里的图片上传组件的前后端实现原理(React + Node),花了一些时间,希望对...

    cfanr 评论0 收藏0
  • H5拖放+FormData接口+NodeJS,完整异步文件上传(一)

    摘要:前段时间面试过程中,频繁遇到异步文件上传的相关问题。所以,这会是一个拖放接口实现文件异步上传的完整。监听放置元素的事件,通过对象可以获得拖拽事件的状态及数据。后端文件接收保存后端使用实现文件上传。   前段时间面试过程中,频繁遇到H5异步文件上传的相关问题。还遇到过一个通过H5拖放功能实现文件异步上传的问题,大概知道H5有新增拖拽功能可以接收文件,如何异步上传文件就母鸡了(摊手)。面试...

    NervosNetwork 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<