node_上传文件multer+上传文件Ajax+文件下载_file.originalname_small_rain_的博客-程序员秘密

技术标签: node.js  前端的进步  

非原创

本文转自https://github.com/a415432669/-front_end_notebook/tree/master/Node/day6/%E6%96%87%E6%A1%A3

 

 

一、multer中间件

再上传文件时,我们通常会使用到他。Multer用于处理multipart/form-data 类型的表单数据。首先我们先安装它:
cnpm install multer --save

二、使用

首先在form表单中我们需要设置enctype为:multipart/form-data表单类型。同时我们也需要用到fs模块对文件重命名。下面是单文件上传实例:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
    </head>
    <body>
        <form action="http://localhost:8080/" method="post" enctype="multipart/form-data">
            <input type="file" name="files" value="指定文件">
            <br><br>
            <input type="submit" value="上传">
        </form>
    </body>
</html>

 

const express=require("express");
const multer=require('multer');
//初始化上传对象
var upload=multer({dest:'./upload/'});
var fs = require('fs');


var app=express();

app.use("/",upload.single("files"),function(req,res){    //files为input type="file"的name值
    var oldFile=req.file.destination+req.file.filename;    //指定旧文件
    var newFile=req.file.destination + req.file.originalname;    //指定新文件
    fs.rename(oldFile,newFile,function(err){
        if(err){
            res.send('上传失败!');
        }else{
            res.send('上传成功!');
        }
    });
});

app.listen(8080);

在这里我们可以指定单个文件上传到根目录的upload文件夹里。这里值得注意的是req.file会返回文件的基本信息:
  fieldname: ***,    //input type="file"的name值
  originalname: ***,    //用户计算机上的文件的名称
  encoding: '***',        //文件编码
  mimetype: ***',        //文件的 MIME 类型
  destination: './***/',        //保存路径
  filename: ***,        //保存在 destination 中的文件名
  path: ***,        //已上传文件的完整路径
  size: **        //文件大小(字节单位)

三、上传多个文件

在HTML找中input type="file"需要加上multiple来实现过滤,multiple不写参数则可以读取·所有文件。而在服务端上,我们需要将single()改为array(“name”,num);的形式来接收多个文件的上传请求。最后对他们全部进行重命名。在这之前我们首先看看multer支持哪些文件上传方式:

.single(fieldname)    //接受一个以 fieldname 命名的文件。.fields(fields)
.array(fieldname[, maxCount])    //接受一个以 fieldname 命名的文件数组。可以配置 maxCount 来限制上传的最大数量。
.fields(fields)    //接受指定 fields 的混合文件。fields是一个拥有name和maxCount的数组对象。
.none()        //只接受文本域。如果任何文件上传到这个模式,将发生 "LIMIT_UNEXPECTED_FILE" 错误。
.any()    //接受一切上传的文件。

下面我们将会演示如何上传多个文件:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
    </head>
    <body>
        <form action="http://localhost:8080/" method="post" enctype="multipart/form-data">
            <input type="file" name="files" value="指定文件" multiple>
            <br><br>
            <input type="submit" value="上传">
        </form>
    </body>
</html>

 

const express=require("express");
const multer=require('multer');
var upload=multer({dest:'./upload/'});
var fs = require('fs');


var app=express();

app.use("/",upload.array("files",5),function(req,res,next){
    req.files.forEach(function(ele,index){
        console.log(ele);
        var oldFile=ele.destination+ele.filename;    //指定旧文件
        var newFile=ele.destination+ele.originalname;    //指定新文件
        fs.rename(oldFile,newFile,function(err){
            err?console.log('上传失败!'):console.log('上传成功!');
        });
    });
    res.send("成功上传");
});

app.listen(8080);

这里,我们获取文件信息是通过req.files来获取,他是由数组构成的对象,之后用foreach循环对其进行重命名即可。

四、通过limits来限制上传文件

Multer通过使用limits这个对象来对数据进行限制,它允许使用以下参数:

Key    Description    Default
fieldNameSize    field 名字最大长度    100 bytes
fieldSize    field 值的最大长度    1MB
fields    非文件 field 的最大数量    无限
fileSize    在 multipart 表单中,文件最大长度 (字节单位)    无限
files    在 multipart 表单中,文件最大数量    无限
parts    在 multipart 表单中,part 传输的最大数量(fields + files)    无限
headerPairs    在 multipart 表单中,键值对最大组数    2000


如果你上传的文件超出这些设定,MulterError模块将会启用,该模块在node_modules/multer/lib/multer-error.js上:
 

我们可以使用err.code定位到该错误,他有7种code方式,不同设置会返回不同code;

LIMIT_PART_COUNT
LIMIT_FILE_SIZE
LIMIT_FILE_COUNT
LIMIT_FIELD_KEY
LIMIT_FIELD_VALUE
LIMIT_FIELD_COUNT
LIMIT_FIELD_COUNT


下面就给大家做个简单实例:
html依然不变,js代码如下:

var upload=multer({dest:'./upload/',limits:{fileSize: 1024 * 1024 * 20,files: 5}});

fileSize: 1024 * 1024 * 20,设置的大小为20m;files限制上传的数量;

const express=require("express");
const multer=require('multer');
var upload=multer({dest:'./upload/',limits:{fileSize: 1024 * 1024 * 20,files: 5}});
var fs = require('fs');

var app=express();

app.use("/",upload.array("files",5),function(req,res,next){
    req.files.forEach(function(ele,index){
        var oldFile=ele.destination+ele.filename;    //指定旧文件
        var newFile=ele.destination+ele.originalname;    //指定新文件
        fs.rename(oldFile,newFile,function(err){
            err?console.log('上传失败!'):console.log('上传成功!');
        });
    });
    next();
    res.send("上传成功!");
});

app.use(function(err,req,res,next){
    if (err.code==='LIMIT_FILE_SIZE'){
        res.send('File is too large');
    }else if(err.code==='LIMIT_FILE_COUNT'){
        res.send('Too many files');
    }
})

app.listen(8080);

图片处理:用开源图像处理软件Open...;node间接让c跑图片处理插件,node处理图像性能很差,必须调用插件

app.js

var cookieParser = require('cookie-parser');

let session = require('express-session');

let uploadRouter = require('./routes/uploadRouter');

app.use('/imgUpload', uploadRouter);

 

uploadRouter.js

var express = require('express');
var router = express.Router();
// 引入上传模块
let multer = require('multer');
// 配置上传对象
let upload = multer({
    dest: "./public/upload"
});

var fs = require('fs');


/* GET users listing. */
router.get('/', function (req, res, next) {
    res.render('uploadimg.ejs');
});

// 处理上传的post请求
// 如果上传单个文件,可调用upload.single('imgfile')方法,并且将表单文件的name值传入
router.post('/', upload.single('imgfile'), function (req, res) {
    console.log(req.file);
    // 因为直接上传的文件为随机名字,我们想要重新命名
    let oldPath = req.file.destination + "/" + req.file.filename;
    let newPath = req.file.destination + "/" + req.file.filename + req.file.originalname;
    fs.rename(oldPath, newPath, () => {
        console.log("改名成功");
    })
    res.send("<h1>上传成功</h1><img src='/upload/" + req.file.filename + req.file.originalname + "'/>");
})


module.exports = router;

uploadimg.ejs

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <h1>图片上传</h1>
    <!-- 表单上传文件时,需改变属性enctype为enctype="multipart/form-data",即定义表单的上传类型为文件类型 -->
    <form action="/imgUpload" method="POST" enctype="multipart/form-data">
        <input type="file" name="imgfile">
        <button type="submit">上传</button>
    </form>
</body>

</html>

 

 

 

AJAX上传图片

图片上传实现步骤

图片上传

通过jquery监听input change事件,这样我们可以获取到上传的图片流信息,从而可以获取到图片的地址、大小、格式以及名称等信息

这里创建3个数组,imgName、imgSrc、imgFile分别用于存放上传图片的名称、url地址以及图片流信息

var fileList = this.files;
        for(var i = 0; i < fileList.length; i++) {
            var imgSrcI = getObjectURL(fileList[i]);
            imgName.push(fileList[i].name);
            imgSrc.push(imgSrcI);
            imgFile.push(fileList[i]);
        }

getObjectURL方法是一个用于获取本地图片的地址,使用该url可以显示图片

function getObjectURL(file) {
    var url = null ;
    if (window.createObjectURL!=undefined) { // basic
        url = window.createObjectURL(file) ;
    } else if (window.URL!=undefined) { // mozilla(firefox)
        url = window.URL.createObjectURL(file) ;
    } else if (window.webkitURL!=undefined) { // webkit or chrome
        url = window.webkitURL.createObjectURL(file) ;
    }
    return url ;
}

控制上传图片大小、格式以及上传数量

$('#upload').on('change',function(){        
          if(imgSrc.length==4){
            return alert("最多只能上传4张图片");
        }
        var imgSize = this.files[0].size;  //b
        if(imgSize>1024*1024*1){//1M
            return alert("上传图片不能超过1M");
        }
        if(this.files[0].type != 'image/png' && this.files[0].type != 'image/jpeg' && this.files[0].type != 'image/gif'){
            return alert("图片上传格式不正确");
        }
    })

图片预览

创建一个addNewContent方法用于动态展示添加的图片实现图片预览,在每次上传图片的时候调用该方法

function addNewContent(obj) {
    $(obj).html("");
    for(var a = 0; a < imgSrc.length; a++) {
        var oldBox = $(obj).html();
        $(obj).html(oldBox + '<li class="content-img-list-item"><img src="'+imgSrc[a]+'" alt=""><a index="'+a+'" class="hide delete-btn"><i class="ico-delete"></i></a></li>');
    }
}

图片删除

1.通过监听鼠标的mouseover事件,显示图片删除按钮

$('.content-img-list').on('mouseover','.content-img-list-item',function(){

        $(this).children('a').removeClass('hide');

    });

2.监听鼠标的mouseleave事件,隐藏图片删除按钮

$('.content-img-list').on('mouseleave','.content-img-list-item',function(){
        $(this).children('a').addClass('hide');
    });

3.获取图片index下标属性,通过js的splice方法删除数组元素,重新调用addNewContent方法遍历图片数组显示预览图片

$(".content-img-list").on("click",'.content-img-list-item a',function(){
            var index = $(this).attr("index");
            imgSrc.splice(index, 1);
            imgFile.splice(index, 1);
            imgName.splice(index, 1);
            var boxId = ".content-img-list";
            addNewContent(boxId);
            if(imgSrc.length<4){//显示上传按钮
                $('.content-img .file').show();
            }
      });

图片上传提交

这里主要使用FormData来拼装好数据参数,提交到后台

var formFile = new FormData();

遍历imgFile图片流数组拼装到FormData中

$.each(imgFile, function(i, file){
            formFile.append('myFile[]', file);
        });

添加其他参数

formFile.append("type", type); 
formFile.append("content", content); 
formFile.append("mobile", mobile); 

最后使用ajax提交内容

 $.ajax({
            url: 'http://zhangykwww.yind123.com/webapi/feedback',
            type: 'POST',
            data: formFile,
            async: true,  
            cache: false,  
            contentType: false, 
            processData: false, 
            // traditional:true,
            dataType:'json',
            success: function(res) {
                console.log(res);
            }
        })

以上就实现了图片上传、图片预览和图片删除的功能

jquery设置 ajax属性

processData : false, // 告诉jQuery不要去处理发送的数据
contentType : false,// 告诉jQuery不要去设置Content-Type请求头

 

整体代码:

uploadRouter.js

var express = require('express');
var router = express.Router();
// 引入上传模块
let multer = require('multer');
// 配置上传对象
let upload = multer({
    dest: "./public/upload"
});

var fs = require('fs');


/* GET users listing. */
router.get('/', function (req, res, next) {
    res.render('uploadimg.ejs');
});

// 处理上传的post请求
// 如果上传单个文件,可调用upload.single('imgfile')方法,并且将表单文件的name值传入
// router.post('/', upload.single('imgfile'), function (req, res) {
//     console.log(req.file);
//     // 因为直接上传的文件为随机名字,我们想要重新命名
//     let oldPath = req.file.destination + "/" + req.file.filename;
//     let newPath = req.file.destination + "/" + req.file.filename + req.file.originalname;
//     fs.rename(oldPath, newPath, () => {
//         console.log("改名成功");
//     })
//     res.send("<h1>上传成功</h1><img src='/upload/" + req.file.filename + req.file.originalname + "'/>");
// })


router.post('/', upload.single('imgfile'), function (req, res) {
    console.log(req.file);
    // 因为直接上传的文件为随机名字,我们想要重新命名
    let oldPath = req.file.destination + "/" + req.file.filename;
    let newPath = req.file.destination + "/" + req.file.filename + req.file.originalname;
    fs.rename(oldPath, newPath, () => {
        console.log("改名成功");
    })
    // ajax传过去应该是json字符串
    res.json({
        state: 'ok',
        imgUrl: "/upload/" + req.file.filename + req.file.originalname
    })
})

router.get('/ajax', (req, res) => {
    res.render('uploadajax');
})


module.exports = router;

uploadAjax.ejs

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <h1>图片上传</h1>
    <!-- 表单上传文件时,需改变属性enctype为enctype="multipart/form-data",即定义表单的上传类型为文件类型 -->
    <form id="uploadForm" action="/imgUpload" method="POST" enctype="multipart/form-data">
        <label for="imgInput">选择文件</label>
        <input hidden id="imgInput" type="file" name="imgfile">
        <div class="btn">上传</div>
    </form>
    <div>
        <h3>预览</h3>
        <img id="imgLook" src="" alt="">
    </div>

    <script src='/javascripts/jquery.min.js'></script>
    <script>
        let formDataObj = new FormData();
        let file;
        $('#imgInput').change(function (e) {
            // console.log($('#uploadForm'));
            console.log(this.files);
            // 图片预览就是把this.files[0]变成地址之类,别人通过访问你的地址显示这个图
            file = this.files[0];
            // 创建预览图片地址
            let httpUrl = window.webkitURL.createObjectURL(file);
            $('#imgLook').attr("src", httpUrl);

            // 创建formData对象,将文件追加到formData对象里
            // 因为之前uploaadRouter中写的是upload.single('imgfile');所以每次上传一个,而想上传多个,这里就需要每次都会new一次
            formDataObj = new FormData();
            formDataObj.append("imgfile", file);
        })

        $('.btn').click(function () {
            $.ajax({
                url: "/imgUpload",
                method: "POST",
                data: formDataObj,
                processData: false, //不需要处理数据
                contentType: false, //不需要设置类型
            }).then(function (res) {
                console.log(res);
                $('body').append(`<h1>上传成功</h1><img src='${res.imgUrl}'>`);
            })
        })
    </script>
</body>

</html>

 

 

文件下载

文件下载非常简单,仅需通过res.download()执行即可,他可以写为3种形式:
res.download('/report-12345.pdf');

以下是一个对选择对应文件进行下载的实例:
html:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
    </head>
    <body>
        <form action="http://localhost:8080/" method="post" enctype="application/x-www-form-urlencoded">
            <input type="file" name="files" value="选择下载的文件"><br><br>
            <input type="submit" value="下载">
        </form>
    </body>
</html>

js:

const express=require("express");
const bodyParser=require("body-parser");

var app=express();

var jsonParser = bodyParser.json();
var urlencodedParser = bodyParser.urlencoded({ extended: false });

app.post('/',urlencodedParser,function(req,res){
    res.download("./public/"+req.body.files,err=>{
        if(err){
            res.send("下载失败!");
        }else{
            console.log("下载成功!");
        }
    });
});

app.listen(8080);

我们可以选择根目录public下的文件对其进行下载。

 

整体代码:

app.js

let downloadRouter = require('./routes/downloadRouter');

app.use('/download', downloadRouter);

 

downloadRouter.js

var express = require('express');
var router = express.Router();
var sqlQuery = require("../lcMysql");

/* GET home page. */
router.get('/dl/:bookid', async function (req, res, next) {
    let bookid = req.params.bookid;
    // 通过bookid查询数据库,获取本地的文件下载路径
    let sqlStr = 'select localdownload from book where id=?';
    let result = await sqlQuery(sqlStr, [bookid]);
    let localPath = result[0].localdownload;
    res.download(localPath);
});

module.exports = router;

bookInfo.ejs

<div class="localdownload"><a href="/download/dl/10">本地下载</a></div>
        <style>
            .localdownload {
                background: skyblue;
                text-align: center;
                margin-bottom: 200px;
                height: 80px;
                line-height: 80px;
            }

            .localdownload a {
                color: #fff;
                text-decoration: none;
            }
        </style>

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/small_rain_/article/details/112999893

智能推荐

Block的解析_FocusOnLovingFreedom的博客-程序员秘密

一,block是什么?*带有自动变量的匿名函数。 ————引自《iOS与OS X多线程和内存管理》* 1.匿名函数 首先blocks是c语言的扩充功能 c语言中函数是这个样子的:void func() { printf("hello world");}那么,block是一个什么样子的呢?^void () { printf("hello world");}这种不带名的函数就

Linux 设置 ip(动态、静态)_mldxs的博客-程序员秘密

设置动态IP:1、sudo gedit /etc/network/interfaces2、文件修改如下auto eth0 iface eth0 inet dhcp3、sudo /etc/init.d/networking restart设置动态IP:1、同上2、auto eth0iface eth0 inet static add

数据结构与程序架构(一)_vault13的博客-程序员秘密

你项目中的代码是否越来越难以修改和维护?bug越改越多?想知道如何改进设计吗?不妨来看看这篇文章

淘宝订单API获取订单代码说明_代码之路无极限的博客-程序员秘密

淘宝订单测试网址:http://console.open.onebound.cn/console/?i=TurboTrade 数据结构名称 类型 是否隐私 描述 seller_nick String Y 卖家昵称 buyer_nick String Y 买家昵称 title String Y 商品标题 type String Y 交易.

【DDPG】走过的坑,致力于解决action不变化的问题_panbaoran913的博客-程序员秘密

记录一下DDPG/GDDPG训练中出现的问题初始化部分: self.actor_eval = ActorNet(s_dim, a_dim) self.actor_target = ActorNet(s_dim, a_dim) self.critic_eval = CriticNet(s_dim, a_dim) self.critic_target = CriticNet(s_dim, a_dim) # create 2 optimizers for actor and critic self.

2021-10-18委外采购订单无法带出BOM组件问题_St威尔特的博客-程序员秘密

委外采购订单无法带出BOM物料原因分析二最近又遇到一例委外采购订单无法带出BOM物料的问题,按照之前的方式操作没达到效果,后面自己研究了一下好使了。如下做个小记,给其他小伙伴作参考,也便于以后自己查看。一、问题描述采购员创建一个委外采购订单,发现有两个BOM料没有带出来。订单信息及BOM料见下图:二、处理思路:1、对比BOM信息,发现未带出的物料原来并不在BOM清单中,主数据人员后补录系统(10月15日)。2、检查物料主数据、采购信息记录生效时间,未发现异常。按照BOM维护时间要早于需求

随便推点

相机相关知识记录_mono8_皆成旧梦的博客-程序员秘密

相机相关知识记录本文记录一些使用时遇到的相机相关知识,不定期更新。1.相机数据格式mono8,即存储下来的图像为单色,8Bit的图片,一般是bmp,jpeg等。packed mono10,即存储下来的图片为单色,10Bit的图片。packed存储即将10Bit的数据以16Bit的方式填充,剩余的本应填充为0的6个bit被下一帧图片数据填充,这样做可以减少数据量和数据冗余度,节省空间。mo...

安卓开发之OkHttp持久化Cookie_android开发 cookie_韭菜盖饭的博客-程序员秘密

文章预览前言一、OkHttp持久化Cookie分析二、例子2.1、效果前言OkHttp持久化Cookie使用的是OkHttp3–CookieJar 持久化Cookie参考文章https://www.jianshu.com/p/f1df12ceaedchttps://www.jianshu.com/p/1a222a9394ceokhttp3依赖:implementation("com.squareup.okhttp3:okhttp:4.9.0")添加网络权限&lt;uses-permiss

Adobe illustrator CC 2019 错误代码183_adobe illustrator安装失败183_jzttly的博客-程序员秘密

错误代码183事故始源系统环境解决方法事故始源安装Adobe illustrator CC 2019。安装到88%后无法安装弹窗显示“错误代码183”系统环境Win10 1803(只装了office 2016)(禁用了些不需要或不用的服务)解决方法最终解决方法:①必须启动的系统服务:“Microsoft Store 安装服务”②在网卡属性内必须开启 Internet 协议版本 6 (TCP/IPv6)结论:(吐槽:安装PS时这两项都是不需要的,而且为啥要开启IPv6这就很不明白了)①启动

0x0008f484 处的 std::bad_alloc 内存申请失败_为什么先生2012的博客-程序员秘密

转载自:  http://ztbls888.blog.163.com/blog/static/1718175982012230102141390/久别重逢是说,自从在教科书上见过它一面之后,这才是第二次碰面。也就是说,在这些年的编程经历中,从来没有遇到过吧——至少在我印象中是这样的。以至于我都开始怀疑在“平常的”程序中,它是否真正存在了。内存分配,C 里的 malloc (或者配套的函

PHP模板引擎Smarty详解_zend模版引擎如何使用_佐佐吉牧的博客-程序员秘密

Smarty是由Monte Ohrt和Andrei Zmievski写出的PHP模板引擎。它不同于其他的模板引擎,比如FastTemplate或者patTemplate,其中主要原因就是Smarty会将模板转化成PHP脚本,并剔除每次使用该模板时都会出现在解析环节里的用来控制和错误检验的附加码。这个功能使Smarty在大型应用和高流量网站上有优异的表现。Smarty除了模板编译还有很多其他

USACO--starry--模拟_u%m._ZhouMu的博客-程序员秘密

模拟题目的恶心真心不是吹的#include #include #include #include #include using namespace std;const int MAXN = 510;ofstream fout("starry.out");struct Tri{ int x,y; int start_x,start_y; int end_x,en

推荐文章

热门文章

相关标签