0
点赞
收藏
分享

微信扫一扫

node笔记_express结合formidable实现前后端的文件上传

云卷云舒xj 2023-05-28 阅读 79

文章目录

⭐前言

大家好,我是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的介绍
formidable

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参数是二进制文件
file-upload

💖 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
upload.html

⭐后端生成api上传文件到指定目录

  1. 先渲染html的上传页面
  2. 接受文件参数
  3. 处理文件名,避免重名,加上时间撮处理

💖完整的代码块

指定 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处理生成的文件

上传的文件

⭐结束

感谢阅读💖,如有不足欢迎指出!

blue-sky-water

举报

相关推荐

0 条评论