创建Multer存储引擎

5 file-upload node.js express multer

我正在使用Express和Multer设置图片上传。我的路由器处理程序将收到一个带有多个文件的formData:我想将它们处理为多种分辨率,并使用其分辨率名称将其保存在文件夹中:

media
??? w350
?   ??? image1.jpg
?   ??? image2.jpg
??? w600
?   ??? image1.jpg
?   ??? image2.jpg
??? w1200
    ??? image1.jpg
    ??? image2.jpg
Run Code Online (Sandbox Code Playgroud)

要在中间件中处理图像之前,我必须使用自定义存储引擎,因此我开始使用该引擎编写自己的引擎:https : //github.com/gladchinda/advanced-multer-node-source-code/blob/master /helpers/AvatarStorage.js

我的实现是这样。

var _ = require('lodash');
var fs = require('fs');
var path = require('path');
var Jimp = require('jimp');
var mkdirp = require('mkdirp');
var concat = require('concat-stream');
var streamifier = require('streamifier');

// create a multer storage engine
var CustomStorage = function(options) {
    function CustomStorage() {
        return; // Should be empty
    }

    CustomStorage.prototype._createOutputStream = function(filepath, cb, options) {
        var output = fs.createWriteStream(filepath);
        output.on('error', cb);
        output.on('finish', function() {
            cb(null, {
                destination: options.uploadPath,
                baseUrl: options.uploadPath,
                filename: path.basename(filepath),
                storage: options.storage,
            });
        });
        return output;
    };

    // this processes the Jimp image buffer
    CustomStorage.prototype._processImage = function(image, cb, options) {
        var self = this;
        var batch = [];
        var mime = Jimp.MIME_PNG;
        var clone = image.clone();
        // Set image resolutions
        options.sizes.map((item) => {
            var outputStream;
            var image = null;
            var filepath = options.fileName.split('.');

            options.uploadPath = path.join(options.folder, 'w' + item.width);
            // Create path if not exist
            if (options.storage == 'local') {
                !fs.existsSync(options.uploadPath) && mkdirp.sync(options.uploadPath);
            }
            filepath = path.join(options.uploadPath, options.fileName);
            outputStream = self._createOutputStream(filepath, cb, options);
            image = clone.clone().resize(item.width, item.height);
            var image = {
                stream: outputStream,
                image: image,
            };
            batch.push(image);
        });

        batch.forEach((item) => {
            item.image.getBuffer(mime, function(err, buffer) {
                if (options.storage == 'local') {
                    streamifier.createReadStream(buffer).pipe(item.stream);
                }
            });
        });
    };

    CustomStorage.prototype._handleFile = function(req, file, cb) {
        let that = this;
        let options = {
            sizes: [
                {
                    width: 300,
                    height: 150,
                },
                {
                    width: 600,
                    height: 300,
                },
                {
                    width: 1200,
                    height: 600,
                },
            ],
            storage: 'local',
            output: 'jpg',
            fileName: file.originalname,
            fieldName: file.fieldname,
            folder: 'media/images'
        };


        var fileManipulate = concat(function(imageData) {
            Jimp.read(imageData)
                .then(function(image) {
                    that._processImage(image, cb, options);
                })
                .catch(cb);
        });
        file.stream.pipe(fileManipulate);
    };

    return new CustomStorage(options);
};

module.exports = CustomStorage;
Run Code Online (Sandbox Code Playgroud)

它不需要任何选项,因此在路由器中可以使用以下命令进行调用:

import CustomStorage from './CustomStorage';

var storage = CustomStorage();
var upload = multer({ storage: storage });

router.put('/:id', upload.any(), function(req, res, next) {
    console.log('req.files: ', JSON.stringify(req.files, undefined, 2));
});
Run Code Online (Sandbox Code Playgroud)

上传两张图片时,应返回以下内容:

req.files:  [
  {
    "originalname": "fantastic-photo.jpg",
    "encoding": "7bit",
    "mimetype": "image/jpeg",
    "destination": "media/images/Projects/w1200",
    "baseUrl": "media/images/Projects/w1200",
    "filename": "374827017056551892885227324803010320001537184436993.jpg",
    "storage": "local",
    "fieldname": "projects_img"
  },
  {
    "originalname": "fantastic-photo.jpg",
    "encoding": "7bit",
    "mimetype": "image/jpeg",
    "destination": "media/images/Projects/w1200",
    "baseUrl": "media/images/Projects/w1200",
    "filename": "374827017056551892885227324803010320001537184436993.jpg",
    "storage": "local",
    "fieldname": "projects_img"  
    }
]
Run Code Online (Sandbox Code Playgroud)

但是相反,它仅返回第一个图像:

req.files:  [
  {
    "originalname": "fantastic-photo.jpg",
    "encoding": "7bit",
    "mimetype": "image/jpeg",
    "destination": "media/images/Projects/w1200",
    "baseUrl": "media/images/Projects/w1200",
    "filename": "374827017056551892885227324803010320001537184436993.jpg",
    "storage": "local",
    "fieldname": "projects_img"
  },
  {
    "fieldname": "projects_img2"
  }
]
Run Code Online (Sandbox Code Playgroud)

我不明白为什么它不返回第二张图片的数据。任何帮助都将受到欢迎!