前言

在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. QUIC协议详解

    声明 本文可以自由转载但需注明原始链接.本文为本人原创,作者LightningStar,原文发表在博客园.本文主体内容参考论文[1]完成. 介绍 QUIC,发音同quick,是"Quick ...

  2. dependencies与devDependencies中应该放哪些依赖

    网上一般的解释都是,开发环境用devDependencies,生产环境用dependencies,说的很简明,但是这里有个问题是,哪些包需要放到devDependencies中,哪些包需要放到depe ...

  3. 矩池云上安装 NVCaffe教程

    使用的是P100,cuda11.1base镜像 创建虚拟环境 conda create -n py36 python=3.6 conda deactivate conda activate py36 ...

  4. Docker - 安装&测试

    一.什么是Docker Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从 Apache2.0 协议开源. Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级.可移植的容器中 ...

  5. 微信小程序商品发布

    <!--pages/good/good.wxml--> <!--商品发布--> <form bindsubmit="formSubmit"> & ...

  6. 解决github网站打不开的方法

    发现github最近经常抽风,之前发现打不开时就挂个梯子,最近梯子也都被封了,尝试了下改host发现效果挺好,方法如下(Mac电脑): 1.通过站长工具找出DNS地址:进入站长工具网站的域名解析网址: ...

  7. 『现学现忘』Docker常用命令 — 19、容器常用命令(一)

    目录 1.新建并启动容器 2.列出当前所有正在运行的容器 3.退出容器 4.启动容器 5.重启容器 6.停止容器 7.强制停止容器 8.删除已停止的容器 有镜像才能创建容器,这是根本前提. 我们下载一 ...

  8. centeros7 定时任务

    crond是什么? crond 和crontab是不可分割的.crontab是一个命令,常见于Unix和类Unix的操作系统之中,用于设置周期性被执行的指令.该命令从标准输入设备读取指令,并将其存放于 ...

  9. java.sql.SQLException: Unable to load authentication plugin 'caching_sha2_password'.

    原来是mysql5.X,升级到8.X,连接数据库就报错: Unable to load authentication plugin 'caching_sha2_password'. 原因分析: 可能为 ...

  10. 使用 AHK 在 VS Code 中根据上下文自动切换输入法状态

    平常在VS Code打公式,中英文切换一直狂点 Shift 手都快按断了,于是试图用 AutoHotKey 搞一些自动切换输入法程序,让它根据当前输入环境自动切输入法. 之前在网上搜到的是切换键盘的( ...