multer

官网:https://github.com/expressjs/multer/blob/master/doc/README-zh-cn.md

由于单独封装上传文件的功能,需要做的事情比较繁琐这里直接使用multer库来操作

服务器

安装multer

npm i multer@1.4.2

创建路由器

由于图片作为静态资源(除非你想保存base64图片到数据库),所以不需要service层,只需要定义一个路由层就可以

  1. const express = require('express');
  2. const router = express.Router();
  3. const multer = require('multer');
  4. const path = require('path');
  5. const storage = multer.diskStorage({
  6. destination: function (req, file, cb) {
  7. cb(null, path.resolve(__dirname, '../../public/upload'))
  8. },
  9. filename: function (req, file, cb) {
  10. // 时间戳 - 6位随机字符.文件后缀
  11. const timeStamp = Date.now();
  12. const ramdomStr = Math.random().toString(36).slice(-6);
  13. const ext = path.extname(file.originalname);
  14. const filename = `${timeStamp}-${ramdomStr}${ext}`;
  15. cb(null, filename);
  16. }
  17. })
  18. const upload = multer({
  19. storage,
  20. limits: {
  21. fileSize: 1024 * 2014 * 10
  22. },
  23. fileFilter(req, file, cb) {
  24. // 文件名
  25. const extname = path.extname(file.originalname);
  26. const whiteList = ['.jpg', '.gif', '.png', '.jpeg'];
  27. if (whiteList.includes(extname)) {
  28. cb(null, true);
  29. } else {
  30. cb(new Error(`you ext name of ${extname} is not support`));
  31. }
  32. }
  33. });
  34. router.post('/', upload.single('avatar'), function (req, res, next) {
  35. const url = `http://localhost:12306/upload/${req.file.filename}`;
  36. res.send({
  37. success: true,
  38. uid: "0",
  39. name: "IMG.png",
  40. state: "done",
  41. url: url,
  42. downloadURL: url,
  43. imgURL: url,
  44. size: 2000
  45. })
  46. })
  47. module.exports = router;
  1. storage,用来定义图片上传以后保存图片位置和文件名字的信息
    1. const storage = multer.diskStorage({
    2. destination: function (req, file, cb) {
    3. cb(null, path.resolve(__dirname, '../../public/upload'))
    4. },
    5. filename: function (req, file, cb) {
    6. // 时间戳 - 6位随机字符.文件后缀
    7. const timeStamp = Date.now();
    8. const ramdomStr = Math.random().toString(36).slice(-6);
    9. const ext = path.extname(file.originalname);
    10. const filename = `${timeStamp}-${ramdomStr}${ext}`;
    11. cb(null, filename);
    12. }
    13. })
  • destination,定义上传图片的存放的位置
    • req: 请求头部的相关信息
    • file: 上传的文件的相关信息
    • cb: 回调函数,第一个参数表示没有错误产生,否则会直接报错,第二个参数存放文件的文件夹路径
  • filename: 自定义存放文件的文件的名字
    • cb: 回调函数,第一个参数表示没有错误产生,否则会直接报错,第二个参数表示格式化后的文件名
  1. upload :对象
    1. const upload = multer({
    2. storage,
    3. limits: {
    4. fileSize: 1024 * 2014 * 10
    5. },
    6. fileFilter(req, file, cb) {
    7. // 文件名
    8. const extname = path.extname(file.originalname);
    9. const whiteList = ['.jpg', '.gif', '.png', '.jpeg'];
    10. if (whiteList.includes(extname)) {
    11. cb(null, true);
    12. } else {
    13. cb(new Error(`you ext name of ${extname} is not support`));
    14. }
    15. }
    16. });
  • multer返回一个对象,
  • storage: 定义文件存放的路径和文件名
  • limits: 文件大小,字节为单位
  • fileFilter:过滤上传文件
    • 参数: req,请求头,file,文件相关的信息,cb回调函数
    • whiteList: 定义允许上传的文件类型
    • 如果允许就直接回调会truecb(null,true)
    • 如果不允许,直接抛出错误给客户端cb(new Error(you ext name of ${extname} is not support));第一个参数有值,会作为错误处理
  1. 创建路由 ``json router.post('/', upload.single('avatar'), function (req, res, next) { const url =http://localhost:12306/upload/${req.file.filename}`; res.send({

    1. success: true,
    2. uid: "0",
    3. name: "IMG.png",
    4. state: "done",
    5. url: url,
    6. downloadURL: url,
    7. imgURL: url,
    8. size: 2000

    }) })

  1. - 返回的数据格式可以自定义
  2. <a name="W3BL7"></a>
  3. ## 引用上传路由
  4. ```json
  5. app.use('/api/upload', require('./api/upload'))

客户端

原生表单

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <title>Document</title>
  7. </head>
  8. <body>
  9. <form action="/api/upload" method="POST" enctype="multipart/form-data">
  10. <p>
  11. <input type="text" name="a" />
  12. </p>
  13. <p>
  14. <input type="file" name="img" />
  15. </p>
  16. <p>
  17. <button>提交</button>
  18. </p>
  19. </form>
  20. </body>
  21. </html>
  • entype :一定是要写成multipart/form-data,否则会有问题
  • method: post
  • 会直接把文件作为文件对象上传

ajax

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <title>Document</title>
  7. </head>
  8. <body>
  9. <p>
  10. <input type="text" name="a" />
  11. </p>
  12. <p>
  13. <input type="file" name="img" accept="image/*" multiple />
  14. </p>
  15. <p>
  16. <button>提交</button>
  17. </p>
  18. <img src="" alt="" />
  19. <script>
  20. function upload() {
  21. const inpA = document.querySelector("[name=a]");
  22. const inpFile = document.querySelector("[name=img]");
  23. const img = document.querySelector("img");
  24. const formData = new FormData(); //帮助你构建form-data格式的消息体
  25. formData.append("a", inpA.value);
  26. for (const file of inpFile.files) {
  27. formData.append("img", file, file.name);
  28. }
  29. fetch("/api/upload", {
  30. body: formData,
  31. method: "POST",
  32. })
  33. .then((resp) => resp.json())
  34. .then((resp) => {
  35. console.log(resp);
  36. if (resp.code) {
  37. //有错误
  38. alert(resp.msg);
  39. } else {
  40. img.src = resp.data;
  41. }
  42. });
  43. }
  44. document.querySelector("button").onclick = upload;
  45. </script>
  46. </body>
  47. </html>
  • 需要借助new FileReader()来创建文件封装数据格式,否则数据发送到服务器会有问题