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

news2024/10/6 12:20:46

文章目录

    • ⭐前言
    • ⭐安装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的介绍
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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/526304.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Spring篇】Spring入门案例

&#x1f353;系列专栏:Spring系列 &#x1f349;个人主页:个人主页 目录 一、IOC入门案例 1.入门案例思路分析 2.入门案例代码实现 二、DI入门案例 1.入门案例思路分析 2.入门案例代码实现 三、图书推荐 介绍完Spring的核心概念后&#xff0c;接下来我们得思考一个问题…

2023年安徽省中职网络安全跨站脚本攻击

B-4:跨站脚本攻击 任务环境说明: √ 服务器场景:Server2125(关闭链接) √ 服务器场景操作系统:未知 √ 用户名:未知 密码:未知 1.访问服务器网站目录1,根据页面信息完成条件,将获取到弹框信息作为flag提交; 通过尝试知道这里存在xss漏洞

【CVE-2022-26134】Confluence OGNL RCE 漏洞

漏洞描述 远程攻击者在未经身份验证的情况下&#xff0c;可构造OGNL表达式进行注入&#xff0c;实现在Confluence Server或Data Center上执行任意代码。 影响版本 Confluence Server and Data Center > 1.3.0 Confluence Server and Data Center < 7.4.17 Confluenc…

九头蛇3389远程爆破

1.初学KALI hydra&#xff08;海德拉&#xff09;。 实验环境&#xff1a;VM16,虚拟机两台&#xff0c;Windows10系统&#xff0c;KALI系统&#xff0c;用nmap查看目标端口是否开放。 2.在KALI虚拟机上面使用命令nmap查看WIN10的3389端口是否打开。 3.在KALI虚拟机上面建立用…

Java sdk使用加载账户私钥调用合约

Java sdk使用加载账户私钥调用合约 1.智能合约案例 1.2 智能合约的流程 1.2 智能合约详细代码 实现了一个简单的商店功能。它定义了三个结构体&#xff1a;用户、商家和商品&#xff0c;以及对应的映射关系。它提供了一些方法用于注册用户和商家&#xff0c;创建商品&#x…

MVC模式和三层架构

MVC模式和三层架构 MVC模式三层架构MVC与三层架构的联系MVC与三层架构的异同 MVC模式 MVC&#xff08;Model View Controller&#xff09;是软件工程中的一种软件设计模式&#xff0c;它把软件系统分为模型、视图和控制器三个基本部分。用一种业务逻辑、数据、界面显示分离的方…

路由器+Gdbserver+IDA Pro远程调试

最近在复现路由器漏洞&#xff0c;也踩了不少坑&#xff0c;记录一下&#xff0c;希望能对需要的人有一些帮助。使用的路由器型号为RT-AC68U&#xff0c;ARM架构&#xff0c;小端序&#xff0c;Linux内核版本2.6.36&#xff0c;很老&#xff0c;主要的时间也花费在找能支持这个…

2023年最新版kali linux安装教程

一、前期准备 前排提醒&#xff0c;文末有绿色版安装包免费领取&#xff01; 二、VMware虚拟机配置 1、打开vmware&#xff0c;点击创建新的虚拟机 2、选择自定义(高级)选项&#xff0c;点击下一步 3、继续下一步 4、选择【稍后安装操作系统】&#xff0c;然后点击下一步 …

【Mybatis】使用mybatis框架连接mysql数据库详细步骤

和我之前写的通过导入jdbc驱动jar包来连接mysql数据库而言&#xff0c;用mybatis来说可以有很多好处呀&#xff0c;首先mybatis&#xff0c;就是对jdbc的优化方案对吧&#xff0c;&#xff0c;jdbc的硬编码和一些繁琐的操作在使用mybatis的时候我就彻底抛掷脑后了哈哈哈。 同时…

MySQL数据库下载及安装教程(最最新版)

MySQL数据库下载及安装教程&#xff08;最最新版&#xff09; 一、下载mysql数据库二、安装Mysql三、验证是否安装成功&#xff08;一&#xff09;、命令提示符cmd窗口验证&#xff08;二&#xff09;、MySQL控制台验证 一、下载mysql数据库 进入MySQL官方网站&#xff08;htt…

SVG实现中国地图

1.SVG是什么&#xff1f; svg 是Scalable Vector Graphics的缩写&#xff0c;指可伸缩矢量图形&#xff0c;可以用于绘制复杂不规则的控件。 svg绘制原理&#xff0c;就是利用了Path绘制图形。 1&#xff09;svg利用xml定义图形。在xml中就包晗了绘制Path所需的数据。 2&…

创建数据库中,超详细常用的MySQL命令(含解析、图解与全部代码)

目录 系统命令行 MySQL命令行 数据库命令 数据表命令 建表并导入数据 表的其他操作 系统命令行 以下是在系统命令行&#xff0c;已管理员身份运行的情况下&#xff0c;MySQL的一些命令 1.这两条是关闭MySQL服务与开启MySQL服务的命令 net stop MySQL net start MySQL80…

Mysql启动不了怎么回事

mysql 服务无法启动是什么原因&#xff1f; mysql服务无法启动的原因有很多&#xff1a;可能端口被占用&#xff1b;可能my.cnf配置了错误的参数&#xff1b;也有可能没有初始数据库&#xff0c;还有可能是其他原因。大多数原因都可以通过先注销掉原有的服务、重新装载服务、之…

ASIC-WORLD Verilog(5)基础语法下篇

写在前面 在自己准备写一些简单的verilog教程之前&#xff0c;参考了许多资料----asic-world网站的这套verilog教程即是其一。这套教程写得极好&#xff0c;奈何没有中文&#xff0c;在下只好斗胆翻译过来&#xff08;加了自己的理解&#xff09;分享给大家。 这是网站原文&…

k8s中pod使用详解

一、前言 在之前k8s组件一篇中,我们谈到了pod这个组件,了解到pod是k8s中资源管理的最小单位,可以说Pod是整个k8s对外提供服务的最基础的个体,有必要对Pod做深入的学习和探究。 二、再看k8s架构图 为了加深对k8s中pod的理解,再来回顾下k8s的完整架构 三、pod特点 结合上面这…

YOLOv5算法原理与网络结构

YOLOv5算法原理与网络结构 1.1 YOLOv5算法 YOLOv5算法共有4种网络结构&#xff0c;分别是YOLOv5s、YOLOv5m、YOLOv5l和YOLOv5x&#xff0c;这四种网络结构在宽度和深度上不同&#xff0c;原理上基本一样&#xff0c;接下来以 YOLOv5s 为例介绍 YOLOv5网络结构。 图1 YOLOv5网…

基于Java+SpringBoot+Vue前后端分离手机销售商城系统设计和实现

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

软件AutoID Network Navigator设置基恩士扫码枪的使用教程

AutoID Network Navigator可以用来对扫码枪的ip和各参数进行调整 1.设置前的准备 扫码枪的默认ip是192.168.100.1&#xff0c;所以需要先把电脑IP更改为192.168.100.xxx 2.搜索扫码枪 更改电脑IP后打开软件点击绿色的号 选择以太网 出现局域网设置弹窗&#xff0c;若为你设…

为什么说网络安全行业是 IT 行业最后的红利?

一、为什么选择网络安全&#xff1f; 这几年随着我国《国家网络空间安全战略》《网络安全法》《网络安全等级保护 2.0》等一系列政策/法规/标准的持续落地&#xff0c;网络安全行业地位、薪资随之水涨船高。 未来 3-5 年&#xff0c;是安全行业的黄金发展期&#xff0c;提前踏…

《汇编语言》- 读书笔记 - 第1章-基础知识

《汇编语言》- 读书笔记 - 第1章-基础知识 1.1 机器语言1.2 汇编语言的产生1.3 汇编语言的组成1.4 存储器1.5 指令和数据1.6 存储单元1.7 CPU对存储器的读写1.8 地址总线主流CPU的寻址能力 1.9 数据总线1.10 控制总线检测点 1.11.11 内存地址空间(概述)1.12 主板1.13 接口卡1.1…