概述
涉及技术栈:
- 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。
var express = require("express");
var app = express();
app.get('/upload-file.html', function (request, response) {
require('fs').readFile('./upload-file.html', function (err, data) {
response.end(data);
});
});
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包:
npm i express-fileupload
yarn add express-fileupload
注意:express-fileupload属于中间件,必须在Node.js下的express框架下使用。
使用
基本使用
安装完成还需要导入才能使用,所以按照下面的代码进行导入:
var fileUpload = require('express-fileupload');
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环境下。
var express = require("express");
var fileUpload = require('express-fileupload');
var app = express();
app.use(fileUpload());
app.post('/upload',function (request, response) {
console.log(request.files);
});
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 函数把上传的文件保存到指定位置:
var express = require("express");
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;
var uploadPath = __dirname + "/upload/img/" + fileName;
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);
});
利用循环将多个文件保存到指定路径,代码如下:
var express = require("express");
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]);
var formData = new FormData();
formData.append("avatar", document.getElementById("avatar").files[0]);
axios({
method: 'POST',
url: '/upload',
data: formData,
headers: {
"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文件进行提交,如果是那样就会造成跨域的问题。
var express = require("express");
var fileUpload = require('express-fileupload');
var app = express();
app.use(fileUpload());
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;
if (!request.files || Object.keys(request.files).length === 0) {
return response.status(400).send("没有文件被上传!")
}
var fileName = avatarFile.name;
var uploadPath = __dirname + "/upload/img/" + fileName;
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]);
var formData = new FormData();
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);
axios({
method: 'POST',
url: 'http://localhost:8989/upload',
data: formData,
headers: {
"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后端。
var express = require("express");
var fileUpload = require('express-fileupload');
var bodyParser = require('body-parser');
var app = express();
app.use(fileUpload());
app.use(bodyParser.urlencoded({extended: false}));
app.use(bodyParser.json());
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);
console.log(request.files.avatar);
console.log(request.body.username);
console.log(request.body.password);
console.log(request.body.introduction);
});
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-parser 和express-fileupload 中间件来处理。
|