node笔记_express结合formidable实现前后端的文件上传
文章目录
- ⭐前言
- ⭐安装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 uploadconst 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.Messageconst {Message}=Element;// instanceconst 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(); //成功iconthat.$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处理生成的文件

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

相关文章:
node笔记_express结合formidable实现前后端的文件上传
文章目录 ⭐前言⭐安装http请求的文件解析依赖库💖 安装 formidable💖 node formidable接受formData上传参数 ⭐上传的页面搭建💖 vue2 element upload💖 node 渲染 上传文件 ⭐后端生成api上传文件到指定目录💖完整的…...
CKA 09_Kubernetes工作负载与调度 资源调度 三类QoS request 资源需求 limit 资源限额
文章目录 1. 资源调度1.1 准备工作1.2 为什么需要 request 和 limit1.3 内存限制1.3.1 Brustable1.3.2 Guaranteed1.3.3 BestEffort1.3.4 当容器申请的资源超出 limit 和 request 1.4 CPU限制 1. 资源调度 1.1 准备工作 Kubernetes 采用 request 和 limit 两种限制类型来对资源…...
【pytorch】维度变换
【pytorch】维度变换 View操作unSqueeze操作图片处理的一个案例squeeze 维度删减操作维度扩展-expand维度扩展-repeat矩阵的转置操作-transpose View操作 将一个四维的张量(b x c x h x w)转换成一个二维的张量 对于四张图片 将每一张图像用一行向量进…...
vue3中的nextTick()
目录 nextTick() 方法用法回调函数方式使用await方式使用 实现原理使用nextTick() 方法时的注意事项 nextTick() 方法 nextTick() 方法是一个非常强大的工具,是一个等待下一次 DOM 更新刷新的工具方法。用于将一个函数以异步的方式推迟到下一个 DOM 更新周期执行。…...
高效学习传感器|霍尔式传感器
01、霍尔式传感器的工作原理 1●霍尔效应 霍尔式传感器的物理基础是霍尔效应。如图1所示,在一块长度为l、宽度为b、厚度为d的长方体导电板上,左、右、前、后侧面都安装上电极。在长度方向上通入电流I,在厚度方向施加磁感应强度为B的磁场。 ■…...
2023年前端面试高频考点HTML5+CSS3
目录 浏览器的渲染过程⭐⭐⭐ CSS 、JS 阻塞 DOM 解析和渲染 回流(重排)和重绘⭐⭐ 选择器 ID选择器、类选择器、标签选择器(按优先级高到低排序)⭐⭐ 特殊符号选择器(>,,~,空格࿰…...
企业开源测试项目实战(附全套实战项目教程+视频+源码)
接口测试项目 1. No matching distribution found for itypes1.1.0 Could not find a version that satisfies the requirement itypes1.1.0 (from -r requirements.txt (line 8)) (from versions: ) No matching distribution found for itypes1.1.0 (from -r requirements.…...
信创办公–基于WPS的EXCEL最佳实践系列 (创建表格)
信创办公–基于WPS的EXCEL最佳实践系列 (创建表格) 目录 应用背景操作步骤1、新建空白工作簿并命名为“奖牌榜”2、使用模板新建工作簿3、新增一张工作表,并将工作簿的标签更改为红色4、复制与隐藏工作表5、添加工作簿属性值6、更改工作簿主题…...
四、HAL_驱动机械按键
1、开发环境。 (1)KeilMDK:V5.38.0.0 (2)STM32CubeMX:V6.8.1 (3)MCU:STM32F407ZGT6 2、机械按键简介 (1)按键内部是机械结构,也就是内部是没有电路的。按键按下内部引脚导通,松开内部断开。 3、实验目的&原理…...
机器学习实战六步法之数据收集方法(四)
要落地一个机器学习的项目,是有章可循的,通过这六个步骤,小白也能搞定机器学习。 看我闪电六连鞭!🤣 数据收集 数据是机器学习的基础,没有数据一切都是空谈!数据集的数据量和数据的质量往往决…...
神经网络:CNN中的filter,kernel_size,strides,padding对输出形状的影响
输入数据在经过卷积层后,形状一般会发生改变,而形状的变化往往与以下四个超参数有关。 1,filter(out_channel) 该超参数控制着输入数据经过卷积层中需要与几个卷积核进行运算,而输入数据与每个卷积核进行…...
Spring Boot集成Redisson布隆过滤器案例
1 什么是布隆过滤器 布隆过滤器实际上是一个非常长的二进制向量(bitmap)和一系列随机哈希函数。那什么又叫哈希函数呢?哈希函数指将哈希表中元素的关键键值通过一定的函数关系映射为元素存储位置的函数。(HashMap源码) 布隆过滤器的优点&…...
使用 VSCode SSH 公网远程连接本地服务器开发 - cpolar内网穿透
文章目录 前言视频教程1、安装OpenSSH2、vscode配置ssh3. 局域网测试连接远程服务器4. 公网远程连接4.1 ubuntu安装cpolar内网穿透4.2 创建隧道映射4.3 测试公网远程连接 5. 配置固定TCP端口地址5.1 保留一个固定TCP端口地址5.2 配置固定TCP端口地址5.3 测试固定公网地址远程 转…...
portraiture宿主插件最新v4中文版本下载及使用教程
自拍怎么可以不修图呢?如果要修图的话,磨皮就是其中非常重要的一环。皮肤看起来细腻光滑了,整个人的颜值都会瞬间拉高。下面就让我们介绍一下磨皮用什么软件好用,什么软件可以手动磨皮的相关内容。portraiture是ps人像修图中常用的…...
一. ATR技术指标的定义与运用
一. ATR的定义 1. 什么是ATR ATR英文全名是Average true range,翻译过来就是平均真实波幅,这个指标主要用来衡量最近N天TR(真实波幅)的平均值。 2. ATR相关计算公式 T R [ ( 最高价 − 最低价 ) , ( 前一次收盘价 − 最高价 ) ࿰…...
linux find帮助文档
以下是完整的find命令帮助文档: 用法:find [-H] [-L] [-P] [-D debugopts] [-Olevel] [起始路径…] [表达式] 选项: -H 跟随命令行符号链接 -L 跟随所有符号链接 -P 不跟随任何符号链接(默认) -D debugopts 调试标志…...
搜索与图论(acwing算法基础)
文章目录 DFS排列数字n皇后 BFS走迷宫 拓扑序列单链表树与图的深度优先搜索模拟队列有向图的拓扑序列 bellman-ford有边数限制的最短路 spfaspfa求最短路spfa判断负环 FloydFloyd求最短路 PrimPrim算法求最小生成树 KruskalKruskal算法求最小生成树 染色法判定二分图染色法判定…...
【数据结构】何为数据结构。
🚩 WRITE IN FRONT 🚩 🔎 介绍:"謓泽"正在路上朝着"攻城狮"方向"前进四" 🔎🏅 荣誉:2021|2022年度博客之星物联网与嵌入式开发TOP5|TOP4、2021|2022博客之星T…...
【P57】JMeter 保存响应到文件(Save Responses to a file)
文章目录 一、保存响应到文件(Save Responses to a file)参数说明二、准备工作三、测试计划设计 一、保存响应到文件(Save Responses to a file)参数说明 可以将结果树保存到文件 使用场景:当结果太大,使…...
Visual Studio 2022 v17.6 正式发布
Visual Studio 17.6 正式发布,这个最新版本提供了一系列强大的工具和功能,旨在使你能够制作出最先进的应用程序。 提高生产力 通过 Visual Studio 2022,目标是帮助你在更短的时间内完成 IDE 内的所有开发任务,在这个版本中&…...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...
《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...
C++ 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
Spring是如何解决Bean的循环依赖:三级缓存机制
1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间互相持有对方引用,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...
【JVM面试篇】高频八股汇总——类加载和类加载器
目录 1. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...
JavaScript 数据类型详解
JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型(Primitive) 和 对象类型(Object) 两大类,共 8 种(ES11): 一、原始类型(7种) 1. undefined 定…...
接口自动化测试:HttpRunner基础
相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具,支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议,涵盖接口测试、性能测试、数字体验监测等测试类型…...
Linux nano命令的基本使用
参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时,显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...
提升移动端网页调试效率:WebDebugX 与常见工具组合实践
在日常移动端开发中,网页调试始终是一个高频但又极具挑战的环节。尤其在面对 iOS 与 Android 的混合技术栈、各种设备差异化行为时,开发者迫切需要一套高效、可靠且跨平台的调试方案。过去,我们或多或少使用过 Chrome DevTools、Remote Debug…...
【LeetCode】算法详解#6 ---除自身以外数组的乘积
1.题目介绍 给定一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O…...
