前言

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

需求分析

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

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

前端部分

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

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<input type="file" name="file" accept="image/*" onchange="changeImg(event)"/>
<button onclick="submit()">上传</button> <script>
let file = ''
let fileName = '' function submit() {
let data = new FormData()
data.append('imgName', fileName)
data.append('img', file) axios({
method: 'post',
timeout: 2000,
url: 'http://localhost:3000/postApi',
data: data
})
.then(response => {
console.log(response.data)
})
.catch(error => {
console.log(error)
})
} function changeImg(e) {
file = e.target.files.item(0)
// 如果不选择图片
if (file === null) {
return
}
fileName = file.name
}
</script>
</body>
</html>

后端部分

这是本文要介绍的重点,为了用高效流畅的方式来解析文件上传请求,我们先引入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属性

本文转载于:猿2048https://www.mk2048.com/blog/blog.php?id=hbiij2jbh2j

用Node处理文件上传的更多相关文章

  1. Node.js 文件上传 cli tools

    Node.js 文件上传 cli tools byte stream 断点续传 refs xgqfrms 2012-2020 www.cnblogs.com 发布文章使用:只允许注册用户才可以访问!

  2. Node开发文件上传系统及向七牛云存储和亚马逊AWS S3的文件上传

    背景起,有奏乐: 有伟人曰:学习技能的最好途径莫过于理论与实践相结合. 初学Node这货时,每每读教程必会Fall asleep. 当真要开发系统时,顿觉精神百倍,即便踩坑无数也不失斗志. 因为同团队 ...

  3. Node.js文件上传

    Node.js express使用Multer实现文件上传html部分 <div> <h3>文件上传:</h3> 选择一个文件上传: <br/> < ...

  4. node+express实现文件上传功能

    在进行node web开发时,我们可能经常遇到上传文件的问题,这一块如果我们没有经验,可能会遇到很多坑,下面我将跟大家分享一下,实现文件上传的一些方式. 一.node+express文件上传的常用方式 ...

  5. NodeJS+formidable实现文件上传加自动重命名

    前述 本人node初学者,此前使用原生node实现文件上传时遇到了一些困难,只做到了.txt 和.png两中格式的文件可以正常上传,如果上传其他格式文件服务端保存的文件会无法正常打开,原因是对form ...

  6. node.js 在 Express4.0 框架使用 Connect-Busboy 实现文件上传

    node.js下四种post提交数据的方式 今天说分享的是其中一种,就是上传文件. Express 4.0 以后,将功能原子化,高内聚,低耦合,独立出了很多中间件 今天主要分享文件上传 对于conne ...

  7. node应用通过multer模块实现文件上传

    multer用于处理文件上传的nodejs中间件,主要跟express框架搭配使用,只支持表单MIME编码为multipart/form-data类型的数据请求. 如果要处理其他编码的表单数据可以通过 ...

  8. Node.js新手教程——怎样实现文件上传功能

    作者:zhanhailiang 日期:2014-11-16 本文将介绍怎样使用Node.js实现文件上传功能. 1. 初始化项目信息:npm init [root@~/wade/nodejs/node ...

  9. node.js系列(实例):原生node.js+formidable模块实现简单的文件上传

    /** * 原生node.js结合formidable模块实现图片上传改名 * @Author:Ghost * @Date:2016/07/15 * @description: * 1.引入模块htt ...

随机推荐

  1. Bugku CTF_web3

    1.打开网页,得到信息如下 2.在hackbar里构造url如下 3.得到flag 4.本题的考点在于读的懂PHP代码,并且学会构造get参数.

  2. 矩池云上如何修改cuda版本

    cuda版本可能对系统,驱动版本会有影响,修改之前需要先进行确认 1.检查系统版本 source /etc/os-release && echo $VERSION_ID 2.导入apt ...

  3. Mysql基础语法-建库-建表(增、删、改、查、表关联及子查询)

    前言:MySQL是一个数据库管理系统,也是一个关系数据库.它是由Oracle支持的开源软件,MySQL可以在各种平台上运行UNIX,Linux,Windows等.可以将其安装在服务器甚至桌面系统上. ...

  4. linux php 环境word转pdf、excel转pdf、office转pdf

    最近项目中遇到一个需求,将word.excel文件转换成pdf,并且打上水印,我利用的是libreoffice,这个需要Java 的jdk环境.废话不多说,开撸 1.在linux上搭建jdk环境 文章 ...

  5. 面向对象编程(C++篇3)——析构

    目录 1. 概述 2. 详论 2.1. 对象生命周期 2.2. 不一定需要显式析构 2.3. 析构的必要性 3. 总结 1. 概述 类的析构函数执行与构造函数相反的操作,当对象结束其生命周期,程序就会 ...

  6. 2.5 C++STL stack详解

    文章目录 2.5.1引入 2.5.2 代码示例 2.5.3 代码运行结果 总结 2.5.1引入 stack是一种"先进后出"的容器. 不过值得注意的是stack是一种关联容器,是通 ...

  7. [Java编程思想] 第二章 一切都是对象

    第二章 一切都是对象 2.1 用引用操纵对象   创建一个String引用: String s;   这里所创建的只是引用,并不是对象.   创建一个引用的同时便初始化: String s = &qu ...

  8. 分布式 PostgreSQL 集群(Citus),官方快速入门教程

    多租户应用程序 在本教程中,我们将使用示例广告分析数据集来演示如何使用 Citus 来支持您的多租户应用程序. 注意 本教程假设您已经安装并运行了 Citus. 如果您没有运行 Citus,则可以使用 ...

  9. [转载]详解ssh端口转发(二)

    关于使用ssh portforwarding来进行FQ的操作,网络上已经有很多很好的文章,我在这里只是画两个图解释一下. 首先要记住一件事情就是: SSH 端口转发自然需要 SSH 连接,而 SSH ...

  10. K8S原来如此简单(五)Metrics Server与HPA

    什么是HPA https://kubernetes.io/zh/docs/tasks/run-application/horizontal-pod-autoscale/ 我们前面有通过kubectl ...