分享web开发知识

注册/登录|最近发布|今日推荐

主页 IT知识网页技术软件开发前端开发代码编程运营维护技术分享教程案例
当前位置:首页 > 网页技术

express 如何上传文件的原理和实现

发布时间:2023-09-06 01:45责任编辑:白小东关键词:暂无标签

express 上传文件的原理和实现

  1. 原理
  2. formidable
  3. multer
  4. COS

1.原理

1.1 要想了解express上传 我们先看看 nodejs原生上传是怎么实现的

let server = require('http').Server(app);server.listen(3000);

首先为了让express拥有原始http模块的一些功能

请不要使用 bodyParser 之类的中间件 因为不会next到这里 保持尽量原生。

app.post('/upload', async(req, res)=>{ ?var postData = ?''; ?req.on("data", function(postDataChunk) { ?// 有新的数据包到达就执行 ?????postData += postDataChunk; ?}); ?req.on("end", function() { ?// 数据传输完毕 ?????console.log(postData); ?????res.end('up success'); ????// console.log('post data finish receiving: ' + postData ); ?});

接下来前端模拟一个post请求 ajax form表单都行 假设我们传了个

<form action="/cos/upload" ?????enctype="application/x-www-form-urlencoded" ?????method="post"> ???<p>What is your name? <input type="text" name="name"><br><button class="btn-save" type="submit" >提交</button> ???</p></form>

在 post的 content-type="application/x-www-form-urlencoded" 下 后台console.log` 的 postData 应该是 name=xxx
这时候通过一些 querystring 之类的中间件解析出 key value数值 以方便我们操作
bodyParser这个中间件也是封装简化了流程 只要直接去req.body里面取就行。但有个弱点 对于file提交 就不能这么玩了! 那我们继续看看为什么

enctype="application/x-www-form-urlencoded" 改成 enctype= multipart/form-data另外增加个文件提交 再准备1个zip文件

<form action="/cos/upload" ?????enctype="multipart/form-data" ?????method="post"> ???<p>What is your name? <input type="text" name="name"><br>What files are you sending? <input type="file" name="file" id="file"><br><button class="btn-save" type="submit" >提交</button> ???</p></form>

上传zip文件 和填写名称后 后台 console.logpostData 大概长这样

------WebKitFormBoundaryXKLAlaggDlZOVroEContent-Disposition: form-data; name="name"xxxx------WebKitFormBoundaryXKLAlaggDlZOVroEContent-Disposition: form-data; name="file"; filename="wrap.zip"Content-Type: application/zipPK?????bL?y??}??????wrap.jpgUT ?????]?Z??Zux ?????????PS??? ?HBKh?: ???? ??zG" ?一堆乱码

真的很吓人格式 其实除了乱码 还是有点规律 都通过WebKitFormBoundary 分割 还有一些头信息描述 和 文件内容 如果您想了解这些代表什么 请看 传送门

让我们改进下代码 取消掉name字段 end 里生成文件

req.on("end", function() { ?// 数据传输完毕 ??????fs.writeFile('./upload/sss.zip',postData,'binary',function(err){ ?//path为本地路径例如public/logo.png ??????????if(err){ ????????????console.log('保存出错!') ??????????????res.end('up failed'); ??????????}else{ ??????????????console.log('保存成功!') ??????????????res.end('up success'); ??????????} ??????}) ?????// console.log('post data finish receiving: ' + postData ); ??});

这段代码的目的是 接受前端的zip包 然后保存为服务器端的upload文件下sss.zip。 很显然 运行是成功了 也生成了 但双击解压时候就愣逼了 无法打开。 看了下2个zip的大小 很明显已经发送了变化 。原因就出在一些其他的东西也进入了数据体(就是刚才乱码部分) 如果name没取消 那么信息将会更混乱 怎么解决呢?其实也很简单 只是少了个解析中间件 当然也有大神手写 根据一定规则 split啊 正则啊

2.formidable

formidable 就是一款解析软件 npm install 下 和 var formidable = require(‘formidable‘)

app.post('/upload', async(req, res)=>{ ???var form = new formidable.IncomingForm(); ???form.uploadDir = "./upload"; ???//form.keepExtensions = true; 是否保持上传什么后缀 保存什么后缀 默认没有后缀 ???form.parse(req, function(err, fields, files) { ???????????res.writeHead(200, {'content-type': 'text/plain'}); ???????????res.write('received upload:\n\n'); ???????????var tmpPath=files.file.path; //临时保存路径 ???????????var fileName=files.file.name; ???????????fs.rename(tmpPath,path.resolve(form.uploadDir,fileName),function (err) { ???????????????if(err){ ???????????????????console.log('保存出错!') ???????????????} ???????????????else{ ???????????????????console.log('保存成功!') ???????????????} ???????????????res.end(); ???????????}) ???????});

然后打开生成的zip文件。这次能正常解压 说明数据没发生破坏。 formidable 也有很多 事件驱动api 如 progress error 等 具体看文档

这里我原名保存了上传文件 按实际情况定义。

3.Multer

multer 就是一款express官方推荐的上传中间件 。和formidable 差不多 但是官方送的最基础的上传 如果你想扩展功能 如上传进度条,断点续传 阿里oss 腾讯cos 等内容仓库 还要你自己想办法 融进去。github上已经有部分写好的 可以去看看 这里给出我的配置 可以参考参考

let setMulter = require('../util/myMulter');//文件上传服务router.post('/upload', ?function (req, res, next) ?{ ?//这是自己写的一个封装势力 为了想以后扩展 ?var upload=setMulter('file',1); ?upload(req, res, function (err) { ????????try { ?????????????if (err) throw err; ?????????????if(req.files.length==0) throw new ?Error("不能上传空文件"); //官方没有空文件的办法 再这里添加 ????????????res.send('文件上传成功'); ????????} ????????catch (err) { ????????????????console.log(err.message); ????????????????res.send(`文件上传失败,原因:${err.message}`); ????????} ??});});

** myMulter.js **

let path=require('path');let multer = require('multer');//api https://github.com/expressjs/multer/blob/master/doc/README-zh-cn.mdlet dir=path.resolve(__dirname,'../upload');const mimes = { ???'.png': 'image/png', ???'.gif': 'image/gif', ???'.jpg': 'image/jpeg', ???'.jpeg': 'image/jpeg', ???'.zip':'application/zip'};//定义仓库const storage = multer.diskStorage({ ???//Note:如果你传递的是一个函数,你负责创建文件夹,如果你传递的是一个字符串,multer会自动创建 ???destination: function (req, file, cb) { ???????cb(null, dir); ???}, ???//获取文件MD5,重命名,添加后缀,文件重复会直接覆盖 ???filename: function (req, file, cb) { ???????var ext =(file.originalname).split('.').pop(); ???????cb(null, `${file.fieldname}-${Date.now()}.${ext}`); ???}});//定义过滤器const fileFilter =function ?(req, file, cb) { ???// 指示是否应接受该文件 ???var test = Object.values(mimes).filter(function(type) { ???????return type===file.mimetype; ???}) ???// 接受这个文件,使用`true`,像这样: ???if(test){ ???????cb(null, true); ???}else{ // 拒绝这个文件,使用`false`,像这样: ???????cb(new Error('file mimes not allow!'), false); ???}}//定义限制const limits={ ???fileSize:1024 * 1024 * 30};module.exports=function(opt) { ???return ?multer({ ???????storage: storage, ???????fileFilter:fileFilter, ???????limits: limits, ???}).array(opt);};

如果你想添加进度条 请参考 这个

4.COS

目前再研究中。。。

express 如何上传文件的原理和实现

原文地址:https://www.cnblogs.com/lanbosm/p/8531862.html

知识推荐

我的编程学习网——分享web前端后端开发技术知识。 垃圾信息处理邮箱 tousu563@163.com 网站地图
icp备案号 闽ICP备2023006418号-8 不良信息举报平台 互联网安全管理备案 Copyright 2023 www.wodecom.cn All Rights Reserved