NodeJS入门之 文件上传

NodeJS入门之文件上传

一.前言

文件上传,在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/*">

注意,不要用此来作为唯一的验证工具,服务端也要验证

猜你喜欢

转载自blog.csdn.net/liuqiao0327/article/details/105259447