文章目录
- ⭐前言
- ⭐安装http请求的文件解析依赖库
- ? 安装 formidable
- ? node formidable接受formData上传参数
- ⭐上传的页面搭建
- ? vue2 element upload
- ? node 渲染 上传文件
- ⭐后端生成api上传文件到指定目录
- ?完整的代码块
- ?效果图
- ⭐结束
⭐前言
大家好,我是yma16,本期分享node使用express结合formidable实现前后端联调的文件上传
往期文章
node_windows环境变量配置
node_npm发布包
linux_配置node
node_nvm安装配置
node笔记_http服务搭建(渲染html、json)
node笔记_读文件
node笔记_写文件
node笔记_连接mysql实现crud
⭐安装http请求的文件解析依赖库
? 安装 formidable
$ npm install formidable
? node formidable接受formData上传参数
查看 readme的介绍
const hostname = '127.0.0.1';
const port = 3000;
const express = require("express");
const formidable = require('formidable');
const app = express();
app.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
app.get("/", (req, res) => {
console.log(__dirname)
res.json({
code: 200,
data: 'yma16 blog',
msg: 'csdn node challenge'
})
});
app.post('/uploadFile/action', (req, res, next) => {
// parse a file upload
const form = new formidable({multiples: true});
// parse 解析
form.parse(req, (err, fields, files) => {
console.log('req', req)
console.log('err,', err)
console.log('fields,', fields)
console.log('files,', files)
if (err) {
next(err);
return;
}
// json返回
res.json({
fields,
files
});
})
})
⭐上传的页面搭建
使用formData上传二进制文件
? vue2 element upload
这里使用vue2和element实现上传
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>elementui vue2 上传文件</title>
<!-- vue2 生产环境版本,优化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<!-- 引入样式 -->
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
<!-- 引入组件库 -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<!-- axios -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<style>
#app {
position: absolute;
height: 100vh;
width: 100vw;
}
.upload-container {
position: relative;
width: 100%;
height: 100%;
}
.upload-container-box {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
.container-title {
position: relative;
width: 100%;
font-size: 24px;
font-weight: bold;
text-align: center;
}
</style>
<body>
<div id="app">
<div class="container-title">
{{ message }}
</div>
<div>
<!-- 文件上传 先关闭自动上传-->
<div class="upload-container-box">
<template>
<!-- :action="uploadForm.uploadUrl"-->
<el-upload class="upload-demo" :accept="uploadForm.accept" ref="uploadRef" drag
:onRemove="handleRemove" :onChange="handlChange" :beforeUpload="beforeUpload"
:action="uploadForm.uploadUrl" :autoUpload="uploadForm.autoUpload"
:fileList="uploadForm.fileList" list-type="picture" :httpRequest="designUpload">
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
<div class="el-upload__tip" slot="tip">只能上传单个png、jpg文件</div>
</el-upload>
<div style="text-align: center">
<el-button type="primary" plain @click="submitBtn"
style="margin-top:10px">上传到服务器</el-button>
</div>
</template>
</div>
</div>
</div>
<script type="text/javascript">
// ELEMENT.Message
const {Message}=Element;
// instance
const instanceVue = {
el: '#app',
name:'upload-component',
data() {
const uploadTypeForm = {
text: ["jpg", "png", "jpeg", "svg"]
};
return {
message: 'element 自定义上传',
$message:Message,
uploadForm: {
autoUpload: false,
accept: uploadTypeForm.text.join(","),
uploadUrl: "http://localhost:3000/uploadFile/action", //上传的url 默认空
fileList: []
}
};
},
methods: {
/**
* 文件删除回调
*/
handleRemove(file, fileList) {
this.uploadForm.fileList = fileList;
},
/**
* 选择文件时回调
*/
handlChange(file, fileList) {
this.uploadForm.fileList = fileList;
},
//上传前的回调
beforeUpload: function(file) {
console.info("上传前的钩子", file);
// 关闭自动上传
return false
},
submitBtn() {
if (this.uploadForm.fileList.length <= 0) {
this.$message({
message: "请先选择文件!",
type: "error"
});
}
this.$refs.uploadRef.submit(); //触发自定义上传
},
//自定义上传
designUpload(params) {
console.info("自定义上传", params);
const that = this;
const formData = new FormData();
formData.append("file", params.file);
const header = {
"Content-Type": "mutipart/form-data"
};
//上传的后端接口
const upLoadUrl = that.uploadForm.upLoadUrl;
axios({
url: upLoadUrl,
method: "post",
data: formData,
headers: header
})
.then(res => {
console.info("res", res);
params.onSuccess(); //成功icon
that.$message({
message: "上传成功!",
type: "success"
});
})
.catch(r => {
that.$message.error("上传失败!");
throw Error(r);
});
}
},
}
// 实例化
new Vue(instanceVue);
</script>
</body>
</html>
上传file参数是二进制文件
? node 渲染 上传文件
const hostname = '127.0.0.1';
const port = 3000;
const express = require("express");
const app = express();
app.listen(port,hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
// server your css as static
app.use(express.static(__dirname));
app.get("/", (req, res) => {
res.json({
code:200,
data:'yma16 blog',
msg:'csdn node challenge'
})
});
app.get("/uploadFile", (req, res) => {
res.sendFile(__dirname + "/html/upload.html");
});
渲染 upload.html
⭐后端生成api上传文件到指定目录
- 先渲染html的上传页面
- 接受文件参数
- 处理文件名,避免重名,加上时间撮处理
?完整的代码块
指定 media为上传路径,生成文件名加上时间搓
const hostname = '127.0.0.1';
const port = 3000;
const express = require("express");
const formidable = require('formidable');
const fs = require('fs')
const app = express();
app.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
// server your css as static
app.use(express.static(__dirname));
app.get("/", (req, res) => {
console.log(__dirname)
res.json({
code: 200,
data: 'yma16 blog',
msg: 'csdn node challenge'
})
});
app.get("/uploadFile", (req, res) => {
console.log(__dirname)
res.sendFile(__dirname + "/html/upload.html");
});
function generateFilename(oldFilename) {
//将老的文件名拼上时间戳
let d = new Date();
let names = oldFilename.split(".");
return `${names[0]}_${""+d.getFullYear() + (d.getMonth()+1) + d.getDate() +'_'+ d.getHours() + d.getMinutes() + d.getSeconds()}.${names[1]}`;
}
app.post('/uploadFile/action', (req, res, next) => {
// parse a file upload
// const form = new formidable({multiples: true});
// api回调
const form = new formidable.IncomingForm();
//保持原有扩展名
form.keepExtensions = true;
//设置上传目录
form.uploadDir = __dirname + "/media/";
// parse 解析
form.parse(req, async(err, fields, files) => {
console.log('req', req)
console.log('err,', err)
console.log('fields,', fields)
console.log('files,', files)
if (err) {
next(err);
return;
}
try {
console.log('files.file', files.file)
// 默认名称
const originalFilename = files.file.originalFilename;
// 默认的路径
const filePath= files.file.filepath
//重命名上传的文件
fs.rename(filePath, form.uploadDir + generateFilename(originalFilename), err => {
if (err) {
console.log("重命名失败");
console.log(err);
} else {
console.log("重命名成功!");
}
})
} catch (r) {
next(r)
return
}
// json返回
res.json({
fields,
files
});
})
})
得到的文件流对象
?效果图
前端的接口联调
后端node处理生成的文件
⭐结束
感谢阅读?,如有不足欢迎指出!文章来源:https://uudwc.com/A/wjVw
文章来源地址https://uudwc.com/A/wjVw