Node.js与Express联合中间件express-fileupload使用axios实现文件上传

概述

涉及技术栈:

  • Node.js:使用JavaScript处理后端逻辑。
  • Express:node.js的web框架。
  • express-fileupload:中间件,处理上传的文件。
  • axios:在前端发送POST请求。
  • body-parser:中间件,获取POST请求提交的数据。

Node.js与Express

使用Node.js结合Express搭建web环境。只需要两个文件:

upload-file.html:包含文件上传表单的html页面。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>文件上传</title>
</head>
<body>
<input type="file" name="avatar" id="avatar"><br/>
<button id="upload-button">上传</button>
<script>
    document.getElementById("upload-button").onclick = function () {
      
      
        console.log(document.getElementById("avatar").files[0]);
    }
</script>
</body>
</html>

upload.js:启动node.js的express程序,并渲染upload-file.html文件,可通过http://127.0.0.1:8989/upload-file.html访问该页面来进行文件上传操作。注意,需要安装express包才能使用Express。

// 第一步,引入express
var express = require("express");

// 第二步,创建服务器应用程序,即原来的http.createServer()
var app = express();

// 渲染upload-file.html页面
app.get('/upload-file.html', function (request, response) {
    
    
    require('fs').readFile('./upload-file.html', function (err, data) {
    
    
        response.end(data);
    });
});

// 监听端口,相当于原来的server.listen()
app.listen(8989, function () {
    
    
    console.log("app is running at port 8989.");
});

在这里插入图片描述

express-fileupload中间件

安装

NPM官网:https://www.npmjs.com/package/express-fileupload
GitHub官网:https://github.com/richardgirges/express-fileupload

首先要先安装express-fileupload包:

# With NPM
npm i express-fileupload

# With Yarn
yarn add express-fileupload

注意:express-fileupload属于中间件,必须在Node.js下的express框架下使用。

使用

基本使用

安装完成还需要导入才能使用,所以按照下面的代码进行导入:

// 第一步,引入express
// var express = require("express");
// 引入文件上传模块express-fileupload
var fileUpload = require('express-fileupload');

// 第二步,创建服务器应用程序
// var app = express();
// 配置文件上传模块
app.use(fileUpload());

注意,注释掉的代码就是express环境。

接着就是使用了,通过request.files即可获取到上传的文件对象:

app.post('/upload',function (request, response) {
    
    
   console.log(request.files);
});

上传单个文件

首先准备一个表单:form-upload.html。form标签的三个属性如下:

  • action:表示处理上传文件的请求路径。
  • method:表示请求方式,必须是POST。
  • encType:上传文件必须指定的属性,值是multipart/form-data
<html>
<body>
<form action='http://localhost:8989/upload' method='post' encType="multipart/form-data">
    <input type="file" name="avatar"/>
    <input type='submit' value='上传'/>
</form>
</body>
</html>

在这里插入图片描述接着在app.js中通过`request.files``获取上传的文件对象,注意在express环境下。

// 第一步,引入express
var express = require("express");
// 引入文件上传模块express-fileupload
var fileUpload = require('express-fileupload');

// 第二步,创建服务器应用程序
var app = express();
// 配置文件上传模块
app.use(fileUpload());

// 处理上传文件请求
app.post('/upload',function (request, response) {
    
    
   console.log(request.files);
});

// 监听端口8989,端口号自定义
app.listen(8989, function () {
    
    
    console.log("app is running at port 8989.");
});

控制台打印结果如下:

{
    
    
  avatar: {
    
    
    name: 'IMG1604419343790.jpg',
    data: <Buffer ff d8 ff e0 00 10 4a 46 49 46 00 01 01 00 00 01 00 01 00 00 ff db 00 43 00 0b 09 09 07 09 09 07 09 09 09 09 0b 09 09 09 09 09 09 0b 09 0b 0b 0c 0b 0b ... 53231 more bytes>,
    size: 53281,
    encoding: '7bit',
    tempFilePath: '',
    truncated: false,
    mimetype: 'image/jpeg',
    md5: '5d338cce6c4810989abb1bbe77529a98',
    mv: [Function: mv]
  }
}

其中avatar就是input标签的name属性值,一一对应。所以如果我们要获取到上传文件的数据,即可:

  • request.files.avatar.name: 上传文件的名字。
  • request.files.avatar.data:上传文件数据,是一个Buffer,可以通过writeFile方法写入到本地文件中。
  • request.files.avatar.size:上传文件的大小,单位为字节。
  • request.files.avatar.tempFilePath:临时文件路径。
  • request.files.avatar.truncated:表示文件是否超过大小限制。
  • request.files.avatar.mimetype:文件的mimetype类型。
  • request.files.avatar.md5:文件的MD5值,可用于检验文件。
  • request.files.avatar.mv:将文件移动到服务器上其他位置的回调函数。

知道了上面的属性和方法,就可以进一步利用mv函数把上传的文件保存到指定位置:

// 第一步,引入express
var express = require("express");
// 引入文件上传模块express-fileupload
var fileUpload = require('express-fileupload');

// 第二步,创建服务器应用程序
var app = express();
// 配置文件上传模块
app.use(fileUpload());

app.post('/upload', function (request, response) {
    
    
    var avatarFile = request.files.avatar;
    console.log(avatarFile);
    // 处理文件上传失败
    if (!request.files || Object.keys(request.files).length === 0) {
    
    
        return response.status(400).send("没有文件被上传!")
    }
    // 获取上传文件名
    var fileName = avatarFile.name;// 注意avatar对应input标签的name属性值
    // 设定文件的保存路径
    var uploadPath = __dirname + "/upload/img/" + fileName;
    // 使用mv方法来将上传文件保存到指定路径下
    // mv(filePath, callback)有两个参数:filePath指定是上传文件的保存路径,callback是回调函数用来处理判断是否上传成功并且有一个参数err表示错误对象
    avatarFile.mv(uploadPath, function (err) {
    
    
        if (err)
            return response.status(500).send(err);
        response.send('文件上传成功!');
    });
});

// 监听端口
app.listen(8989, function () {
    
    
    console.log("app is running at port 8989.");
});

注意:上传文件的保存目录一定要先创建,代码是不会自动给你创建的。如/upload/img必须现有这个目录才能上传成功,否则会上传失败。

上传多个文件

express-fileupload支持多个文件的上传。

准备一个可以上传多个文件的表单,如下:

<html>
<head>
    <meta charset="UTF-8">
</head>
<body>
<form action='http://localhost:8989/upload' method='post' encType="multipart/form-data">
    <input type="file" name="my_file_one"/><br/>
    <input type="file" name="my_file_two"/><br/>
    <input type="file" name="my_file_three"><br/>
    <input type='submit' value='上传'/>
</form>
</body>
</html>

然后上传文件的处理逻辑也是类似的:

app.post('/upload', function (request, response) {
    
    
    console.log(request.files.my_file_one.name);
    console.log(request.files.my_file_two.name);
    console.log(request.files.my_file_three.name);
});

在这里插入图片描述

利用循环将多个文件保存到指定路径,代码如下:

// 第一步,引入express
var express = require("express");
// 引入文件上传模块express-fileupload
var fileUpload = require('express-fileupload');

// 第二步,创建服务器应用程序
var app = express();
// 配置文件上传模块
app.use(fileUpload());

app.post('/upload', function (request, response) {
    
    
    var files = request.files;
    for (var key in files) {
    
    
        var file = files[key];
        console.log('正在上传' + file.name + '...');
        // 设定文件的保存路径
        var uploadPath = __dirname + "/upload/img/" + file.name;
        file.mv(uploadPath, function (err) {
    
    
            if (err)
                return response.status(500).send(err);
        })
    }
    response.send("上传成功!");
});

// 监听端口
app.listen(8989, function () {
    
    
    console.log("app is running at port 8989.");
});

使用axios提交数据上传文件

单独上传文件

这次我们就不使用表单来上传文件了,而是使用axios发送Ajax请求来上传文件。准备一个upload-file.html并且引入axios.js:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>文件上传</title>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>
<body>
<input type="file" name="avatar" id="avatar"><br/>
<button id="upload-button">上传</button>
<script>
    // 通过"上传"按钮触发点击事件
    document.getElementById("upload-button").onclick = function () {
      
      
        console.log(document.getElementById("avatar").files[0]);
        // 创建FormData对象
        var formData = new FormData();
        // 将图片添加到FormData对象中,其中"avatar"对应的是input标签中的name属性
        formData.append("avatar", document.getElementById("avatar").files[0]);
        // 发送POST请求上传文件
        axios({
      
      
            method: 'POST',
            url: '/upload',
            data: formData,
            headers: {
      
      
                // 必须修改请求头Content-Type为multipart/form-data才能上传文件
                "Content-Type": "multipart/form-data"
            }
        }).then(function (response) {
      
      
        		 // 响应回来的数据
            console.log(response.data);
        }).catch(function (reason) {
      
      
            console.log(reason);
        })
    }
</script>
</body>
</html>

其中headers属性值是必须的,因为设置了请求头的Content-Type的值为multipart/form-data,这是原来表单的encType属性值。并且要提交数据需要使用FormData对象来存储数据。

upload.js:处理上传文件。这里使用了app.get('/upload-file.html')渲染upload-file.html页面,所以需要访问http://127.0.0.1:8989/upload-file.html打开页面进行上传文件,而不是像前面表单可以直接打开html文件进行提交,如果是那样就会造成跨域的问题。

// 第一步,引入express
var express = require("express");
// 引入文件上传模块express-fileupload
var fileUpload = require('express-fileupload');

// 第二步,创建服务器应用程序
var app = express();
// 配置文件上传模块
app.use(fileUpload());

// 渲染upload-file.html文件
app.get('/upload-file.html', function (request, response) {
    
    
    require('fs').readFile('./upload-file.html', function (err, data) {
    
    
        response.end(data);
    });
});

app.post('/upload', function (request, response) {
    
    
    console.log(request.files);
    var avatarFile = request.files.avatar;// 注意avatar对应input标签的name属性值
    // 处理文件上传失败
    if (!request.files || Object.keys(request.files).length === 0) {
    
    
        return response.status(400).send("没有文件被上传!")
    }
    // 获取上传文件名
    var fileName = avatarFile.name;
    // 设定文件的保存路径
    var uploadPath = __dirname + "/upload/img/" + fileName;
    // 使用mv方法来将上传文件保存到指定路径下
    avatarFile.mv(uploadPath, function (err) {
    
    
        if (err)
            return response.status(500).send(err);
        response.send('文件上传成功!');
    });
});

// 监听端口
app.listen(8989, function () {
    
    
    console.log("app is running at port 8989.");
});

在这里插入图片描述在这里插入图片描述

上传文件并提交参数

我们平时可能会遇到类似于注册页面,其中需要上传头像文件和一些用户信息。用axios实现如下:
upload-file.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>文件上传</title>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>
<body>
<input type="text" name="username" id="username" placeholder="用户名"><br/>
<input type="password" name="password" id="password" placeholder="密码"><br/>
<input type="file" name="avatar" id="avatar" placeholder="头像"><br/>
<textarea name="introduction" id="introduction" cols="30" rows="10" placeholder="个人简介"></textarea>
<button id="upload-button">上传</button>
<script>
    // 通过"上传"按钮触发点击事件
    document.getElementById("upload-button").onclick = function () {
      
      
        console.log(document.getElementById("avatar").files[0]);
        // 创建FormData对象
        var formData = new FormData();
        // 将图片添加到FormData对象中,其中"avatar"对应的是input标签中的name属性
        formData.append("username", document.getElementById("username").value);
        formData.append("password", document.getElementById("password").value);
        formData.append("avatar", document.getElementById("avatar").files[0]);
        formData.append("introduction", document.getElementById("introduction").value);
        // 发送POST请求上传文件
        axios({
      
      
            method: 'POST',
            url: 'http://localhost:8989/upload',
            data: formData,
            headers: {
      
      
                // 必须修改请求头Content-Type为multipart/form-data才能上传文件
                "Content-Type": "multipart/form-data"
            }
        }).then(function (response) {
      
      
            console.log(response.data);
        }).catch(function (reason) {
      
      
            console.log(reason);
        })
    }
</script>
</body>
</html>

upload.js:处理/upload请求在node.js后端。

// 第一步,引入express
var express = require("express");
// 引入文件上传模块express-fileupload
var fileUpload = require('express-fileupload');
// 引入body-parser模块获取POST请求提交的数据
var bodyParser = require('body-parser');

// 第二步,创建服务器应用程序
var app = express();
// 配置文件上传模块
app.use(fileUpload());
// 配置body-parser
app.use(bodyParser.urlencoded({
    
    extended: false}));
app.use(bodyParser.json());

// 渲染upload-file.html文件
app.get('/upload-file.html', function (request, response) {
    
    
    require('fs').readFile('./upload-file.html', function (err, data) {
    
    
        response.end(data);
    });
});

app.post('/upload', function (request, response) {
    
    
    // 获取上传的文件
    console.log(request.files);
    // 获取上传的数据(但不包括文件)
    console.log(request.body);

    // POST请求上传的文件
    console.log(request.files.avatar);// avatar对应input标签的name属性值
    // POST请求上传的普通数据
    console.log(request.body.username);// username对应input标签的name属性值
    console.log(request.body.password);// password对应input标签的name属性值
    console.log(request.body.introduction);// introduction对应textarea标签的name属性值
});

// 监听端口
app.listen(8989, function () {
    
    
    console.log("app is running at port 8989.");
});

访问http://127.0.0.1:8989/upload-file.html进行提交数据。
在这里插入图片描述后端控制台打印如下:

{
    
    
  name: '2020-08-16 10.26.32.jpg',
  data: <Buffer ff d8 ff e0 00 10 4a 46 49 46 00 01 01 00 00 01 00 01 00 00 ff db 00 43 00 08 06 06 07 06 05 08 07 07 07 09 09 08 0a 0c 14 0d 0c 0b 0b 0c 19 12 13 0f ... 206121 more bytes>,
  size: 206171,
  encoding: '7bit',
  tempFilePath: '',
  truncated: false,
  mimetype: 'image/jpeg',
  md5: '945e98483ef62cf98920f0891b454d94',
  mv: [Function: mv]
}
zhangsan
123456
这是一次POST请求行为,上传头像

我们成功获取到了POST提交的普通数据和上传的文件数据,其中分别使用了body-parserexpress-fileupload中间件来处理。

猜你喜欢

转载自blog.csdn.net/cnds123321/article/details/121548117