NodeJS入门之文件上传
文章目录
- NodeJS入门之文件上传
- 一.前言
- 二.安装使用
- 1.安装
- 2.使用
- 3.前端调用
- 3.1.表单调用
- 3.2 ajax调用
- 3.3 axios ajax
一.前言
文件上传,在web开发中经常遇到,也是比较重要的功能.
常用的开源组件有multer,和formidable等,借助这两个组件开源很轻松的搞定文件上传.
Multer是用于处理的node.js中间件
multipart/form-data
,主要用于上传文件。它被编写在busboy 之上,以实现最高效率。
下面我通过express框架+multer进行文件上传的功能讲解
二.安装使用
1.安装
$ npm install multer
2.使用
const express = require('express');
//引入multer组件
const multer = require("multer");
//生成express实例
const app = express();
/**
* 生成 multer 实例 upload
* multer(options)
* options - 配置选项
* dest - 上传文件的一个临时目录地址
*
*/
//multer的实例
const upload = multer({
//存储的目录地址
dest: "./upload"
});
/**
* 处理接收文件上传的路由
* upload.single('name')上传文件的中间件 name表示 上传文件时 name属性指定的名称
*/
app.post('/upload', upload.single("file"), (req, res, next) => {
res.send({ ret_code: '0' });
});
app.listen(3000, () => {
console.log('服务启动成功');
});
通过postman去调用这个方法
当我们去上传文件时,请求头中的Content-Type必须设置为multipart/form-data
multipart/form-data是基于post方法来传递数据的,用来指定请求内容的数据编码格式
注意:这里我做个延伸.在使用multipart/form-data传递数据时,我们nodejs的后台是无法使用req.body来接收数据的,虽然呢,我在之前的博客中 express基础 讲过,body请求头传参使用req.body来接收参数,并且需要设置2个中间件,但是这里设置了请求头为multipart/form-data时,是无法使用req.body来接收的.
//处理json格式 的请求体
app.use(express.json());
//处理 x-www-form-urlencoded这种格式
app.use(express.urlencoded({
extended:true
}));
req.body接收参数的原理为:
1.req.body 默认的值是undefined.当我们通过2个中间件处理之后才有的值
2.express.json() 处理的是 application/json 这种 Content-Type 类型传递过来的值
3.express.urlencoded() 处理的是 application/x-www-form-urlencoded 这种 Content-Type 类型传递过来的值
为什么中间件处理之后,req.body就有值了呢,我之前博客也讲过 express中间件 ,中间件具有的 作用是可以改变请求体和响应对象
而要想得到 multipart/form-data 这种 Content-Type 类型传递过来除了文件之外的参数数据,需要使用 multer 中间件才能做到,req.body 将具有文本域数据,如果存在的话。默认是空对象 {}
通过postman调用这个上传文件地址之后,我们发现,我们服务器的项目根目录下的upload多了一个类似于编码格式的文件,而且没有后缀,这样一长串的字符,实际上是为了在服务器中重名.虽然我们得到了文件,但是显然这并不是我们想要的,服务器根目录是不知道这个文件到底是干嘛的,什么属性,什么格式.当然,如果你这里只是接受图片,我们就不用走下去了,服务器要用的时候,直接加.jpg的格式即可,我们这里是研究的肯定不仅于此.那有什么办法知道这个上传的文件的属性呢?
/**
* 处理接收文件上传的路由
* upload.single('name')上传文件的中间件 name表示 上传文件时 name属性指定的名称
*/
app.post('/upload', upload.single("file"), (req, res, next) => {
console.log(req.file);
res.send({ ret_code: '0' });
});
打印结果:
{
fieldname: 'file', //字段名
originalname: 'QQ*�20200401014740.jpg',//原文件名称
encoding: '7bit', //文件编码
mimetype: 'image/jpeg',//文件的mimetype
destination: './upload',//文件存储的临时目录
filename: 'dd139ab58059373a3ad7ca522044c53f',//生成的文件名
path: 'upload\\dd139ab58059373a3ad7ca522044c53f',//文件地址
size: 47588 //文件大小 默认是字节长度
}
那我们知道了,文件的名称,文件的地址,还有文件的各种属性,那后面的事情就好操作了,该放文件服务器的放文件服务器,该保存数据库的保存数据库.
好了,上面我们讲的是单个文件上传的例子,那我们来探究下多个文件上传,实际上使用multer上传文件,不管是 单个还是多个,都是依赖于multer这个实例的中间件.
单个文件上传使用upload ,upload.array(’’)
.single(fieldname) //接受名称为的单个文件fieldname。单个文件将存储在中req.file。
多个文件上传使用
.array(fieldname[, maxCount])
//接受所有名称为的文件数组fieldname。如果maxCount上传了多个文件,则可以选择出错。文件数组将存储在中 req.files。
多个文件,混合的不同name字段属性 使用
.fields(fields)
//包含文件数组的对象将存储在中req.files。
//fields应该是包含的对象数组,name还可以是maxCount。
//格式为
[
{ name :' avatar ', maxCount :1 } ,
{ name :' gallery ', maxCount :8 }
]
下面来看多个文件上传的示例:
/**
* 多文件上传
* upload.array(fieldname[, maxCount])
*
*/
app.post('/uploadmany', upload.array('file',2), (req, res) => {
console.log(req.files);
res.send({ ret_code: '0' });
});
同样,我们上传多个文件也是没有问题的.服务器目录也多了编码格式的文件
其中req.files打印结果为:
[
{ fieldname: 'file',
originalname: 'QQ*�20200401014740.jpg',
encoding: '7bit',
mimetype: 'image/jpeg',
destination: './upload',
filename: '4bdc78c77ef842e6dc6e13782d1908df',
path: 'upload\\4bdc78c77ef842e6dc6e13782d1908df',
size: 47588 },
{ fieldname: 'file',
originalname: 'JavaScriptا.pdf',
encoding: '7bit',
mimetype: 'application/pdf',
destination: './upload',
filename: 'c0753bd921d64c11253c59384ffc6ea6',
path: 'upload\\c0753bd921d64c11253c59384ffc6ea6',
size: 93790940
}
]
上面size:93790940 转换成MB之后 93790940/1024 /1024 =89.45MB,实际上,上传大文件效率也是挺不错.
讲到了一个 多个文件,混合的不同name字段属性 使用.fields(fields) 的中间件,这里我不做介绍,因为在开发中也不会限制的这么死,指定标签的的name属性字段去上传,基本不怎么用到,当然,有兴趣的可以去研究下,上面我也写了该中间件的调用方式,也可以参考 multer官网
3.前端调用
3.1.表单调用
<!--
action 就是提交的地址
method 请求类型需要设置为 post
特别重要的是
enctype 要设置为 multipart/form-data
设置请求头中 Content-Type 的值
-->
<form action="http://localhost:3000/upload" method="POST" enctype="multipart/form-data">
<!--
type属性必须为 file
name属性为后端要的参数的名字
-->
文件:<input type="file" name="file">
<button type="submit">提交</button>
</form>
3.2 ajax调用
文件:<input type="file" id="myfile" name="file">
<button id="btn" type="button">提交</button>
<script>
$(function () {
$("#btn").click(function () {
//1.生成一个FormData的实例
const formdata = new FormData();
// 2. 给 formData 追加需要传递给后台的参数
// formData.append('传递给后台的参数名', '这个参数名所对应的值')
formdata.append('file', $("#myfile")[0].files[0]);
//注意,取文件的值有所讲究:
/**
* 文件的值不能直接使用 val() 得到
* 需要使用 文件选择框的 DOM 对象上的 files 属性
* files 属性是一个 FileList 伪数组,这个数组中的某一项就是需要的文件信息对象。将这一项做为参数的值即可。
*/
// console.log($('#myFile').val()) // 文件名字,传给后台没有任何作用
// console.log($('#myFile')[0].files[0])//这两个方法等效 jquery取值和原生取值
// console.log(document.getElementById('myFile').files[0])
//3.发送ajax请求
$.ajax({
url: 'http://localhost:3000/upload',
type: 'POST',
// data 直接使用上面生成的 formdata
data: formdata,
processData: false, // 注意
contentType: false, // 注意
success: function (res) {
console.log(res)
alert("上传成功");
}
})
});
});
</script>
3.3 axios ajax
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
var formData = new FormData();
formData.append('file', $('input[name="file"]')[0].files[0]);
axios.post('/upload', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
前端上传文件可以通过设置 accept=“image/gif,image.jpg” 属性来限制上传的文件格式
//只允许上传图片
<input type="file" id="myfile" name="file" accept="image/*">
注意,不要用此来作为唯一的验证工具,服务端也要验证