土豆博客

Nodejs之图片上传

# 一、概述

在web开发中,经常遇到处理图片文件上传的情况,而在Nodejs中处理图片上传的方式有很多,主要是借助于第三方模块来实现,接下来,我分别介绍如何在express框架和在Koa2框架中实现图片上传。

注意若想实现图片上传功能,form表单的enctype属性必须指定为multipart/form-data

<form action="xxx" method="POST" enctype="multipart/form-data">
</form>
# 二、Express框架中实现图片上传

Express中主要借助formidable模块来实现文件上传,formidable是一个用于处理文件、图片、视频等数据上传的模块,支持GB级上传数据处理,支持多种客户端数据提交。有极高的测试覆盖率,非常适合在生产环境中使用。

(1)安装

npm i express 		//安装express
npm i formidable 	//安装formidable

(2)在项目的根目录下新建upload文件夹,作为图片上传存放的路径

(3)新建server.js文件,代码如下:

const express = require("express");
const formidable = require("formidable");
const path = require('path') 
const app = express();

app.use(express.static("./upload")); //开放静态目录

//设置跨域访问
app.all("*", function(req, res, next) {
  //设置允许跨域的域名,*代表允许任意域名跨域
  res.header("Access-Control-Allow-Origin", "*");
  //允许的header类型,*代表允许任意header类型
  res.header("Access-Control-Allow-Headers", "*");
  //跨域允许的请求方式
  res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
  if (req.method.toLowerCase() == "options") {
    res.send(200); //让options尝试请求快速结束
  } else {
    next();
  }
});

app.post("/upload", (req, res) => {
  const form = new formidable.IncomingForm();
  form.multiples = false; //是否支持解析多个上传的文件,如果前台允许上传多个图片,可以设置为true,默认为false
  form.uploadDir = "./upload"; //配置上传路径
  form.keepExtensions = true; //保留原有后缀名
  form.maxFieldsSize = 20 * 1024 * 1024; //文件大小,默认为20m
  form.parse(req, (err, fields, file) => {
    const fileType = file.uploadFile.type
      .substring(file.uploadFile.type.lastIndexOf("/") + 1)
      .toLowerCase(); //获取图片的后缀名
    //判断上传的是否为图片文件
    if (!/(gif|jpg|jpeg|png|webp|svg|bmp)$/.test(fileType)) {
      res.status(400).json({
        code: 400,
        msg: "上传的必须为图片文件"
      });
    } else {
      //返回服务器上存放的真实图片路径,在这里本地测试服务器端口为8888,实际项目中填入真实服务器地址即可
      const filePath = "http://localhost:8888/" + path.parse(file.uploadFile.path).base 
      res.status(200).json({
        code: 200,
        msg: "success",
        path: filePath
      });
    }
  });
});

app.listen(8888, () => {
  console.log("start...");
});

在VS Code中打开终端或在根目录下打开cmd窗口,运行node server.js启动服务器

(4)新建html静态页面,用于上传图片,代码如下:

<!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>
  <form action="http://localhost:8888/upload" method="POST" enctype="multipart/form-data">
    <input type="file" name="uploadFile" id="upload"><br>
    <img id="preview" width="120"><br>
    <input type="submit" value="上传">
  </form>
  
  <script>
      //处理选择图片文件后显示预览图
      var upload = document.querySelector('#upload')
      var preview = document.querySelector("#preview")
      upload.onchange = function () {
          var reader = new FileReader()
          reader.readAsDataURL(this.files[0])
          reader.onload = function () {
              preview.src = reader.result
          }
      }
  </script>
</body>
</html>
# 三、koa2框架中实现图片上传

koa2中实现文件上传的模块用的则是koa-body。模块的一些配置如下:

(1)koa-body 的基本参数

参数名 描述 类型 默认值
patchNode 将请求体打到原生 node.js 的ctx.req Boolean false
patchKoa 将请求体打到 koa 的 ctx.request Boolean true
jsonLimit JSON 数据体的大小限制 String / Integer 1mb
formLimit 限制表单请求体的大小 String / Integer 56kb
textLimit 限制 text body 的大小 String / Integer 56kb
encoding 表单的默认编码 String utf-8
multipart 是否支持 multipart-formdate 的表单 Boolean false
urlencoded 是否支持 urlencoded 的表单 Boolean true
text 是否解析 text/plain 的表单 Boolean true
json 是否解析 json 请求体 Boolean true
jsonStrict 是否使用 json 严格模式,true 会只处理数组和对象 Boolean true
formidable 配置更多的关于 multipart 的选项 Object {}
onError 错误处理 Function function(){}
stict 严格模式,启用后不会解析 GET, HEAD, DELETE 请求 Boolean true

(2)formidable的相关配置参数

参数名 描述 类型 默认值
maxFields 限制字段的数量 Integer 1000
maxFieldsSize 限制字段的最大大小 Integer 2 * 1024 * 1024
uploadDir 文件上传的文件夹 String os.tmpDir()
keepExtensions 保留原来的文件后缀 Boolean false
hash 如果要计算文件的 hash,则可以选择 md5/sha1 String false
multipart 是否支持多文件上传 Boolean true
onFileBegin 文件上传前的一些设置操作 Function function(name,file){}

(3)安装依赖

npm i koa koa-static koa-body koa-router

(4)根目录下新建upload文件夹,用于存放上传的图片文件

(5)前台代码不变,后台server.js代码如下

const Koa = require("koa");
const static = require("koa-static"); //处理静态资源的访问
const Body = require("koa-body");
const path = require("path");
const Router = require("koa-router");

const app = new Koa();
const router = new Router();

app.use(async (ctx, next) => {
  //允许来自所有域名请求(不携带cookie请求可以用*,如果有携带cookie请求必须指定域名)
  ctx.set("Access-Control-Allow-Origin", "*");
  // 设置所允许的HTTP请求方法
  ctx.set("Access-Control-Allow-Methods", "OPTIONS, GET, PUT, POST, DELETE");
  //允许的header类型,*代表允许任意header类型
  ctx.set("Access-Control-Allow-Headers", "*");
  if (ctx.method == "OPTIONS") {
    ctx.body = "";
    ctx.status = 200;
  } else {
    await next();
  }
});
app.use(
  Body({
    multipart: true, //支持文件上传
    formidable: {
      uploadDir: path.join(__dirname, "./upload"), //设置上传的文件路径
      keepExtensions: true, //保持原有扩展名
      maxFileSize: 20 * 1024 * 1024 //文件上传大小,20M
    }
  })
);
app.use(static(__dirname + "/upload")); //开放静态目录

router.post("/upload", async (ctx) => {
  const fileType = ctx.request.files.uploadFile.type
  .substring(ctx.request.files.uploadFile.type.lastIndexOf("/") + 1)
  .toLowerCase(); //获取图片的后缀名
  //判断上传的是否为图片文件
  if (!/(gif|jpg|jpeg|png|webp|svg|bmp)$/.test(fileType)) {
    ctx.status = 400
    ctx.body = {
        code: 400,
        msg: "上传的必须为图片文件"
    }
  } else {
      //返回服务器上存放的真实图片路径,在这里本地测试服务器端口为8888,实际项目中填入真实服务器地址即可
    const filePath = "http://localhost:8888/" + path.parse(ctx.request.files.uploadFile.path).base 
    ctx.body = {
      code: 200,
      msg: "success",
      path: filePath
    }
  }
});

app.use(router.routes()).use(router.allowedMethods());
app.listen(8888, () => {
  console.log("start...");
});
code
top

扫码添加,一起进步

wechat-code

为了保障最佳预览体验,博客已不支持IE浏览器的访问,邀请您使用以下现代高级浏览器。

谷歌浏览器(推荐) 火狐浏览器

注:如果你使用的是360,QQ等双核浏览器,请开启极速模式