使用Multer和ExpressJS上传文件时的错误处理

17

我正在使用multer来通过 express & nodejs 开发的服务器保存文件。

我正在使用以下代码。

var express = require('express'),
    multer  = require('multer')

var app = express()

app.get('/', function(req, res){
  res.send('hello world');
});

app.post('/upload',[ multer({ dest: './uploads/'}), function(req, res){

    res.status(204).end()
}]);

app.listen(3000);

Multer会将文件保存到指定的目标文件夹。

所有这些都运行良好,但我有以下问题:

  1. 如果出现各种原因导致文件保存失败,似乎我的路由将始终返回状态码204。
  2. 我不确定状态码204是在文件保存后返回还是在异步保存文件时返回。

1
对于 2022 年,需要注意的是,如果 multer 出现错误,它会简单地传递到您的常规 Express 错误路由。如果出于某种原因您需要单独处理它,请参考 Arya 的代码。 - Fattie
9个回答

24

这是如何编写处理上传和错误的multer中间件

const multer = require("multer");

function uploadFile(req, res, next) {
    const upload = multer().single('yourFileNameHere');

    upload(req, res, function (err) {
        if (err instanceof multer.MulterError) {
            // A Multer error occurred when uploading.
        } else if (err) {
            // An unknown error occurred when uploading.
        }
        // Everything went fine. 
        next()
    })
}

请注意,如果您编写响应,则不应调用next(),如果我理解正确的话。 - Aaron
2
接受的答案不再有效,这个应该成为被接受的答案。 - Prince Singh

15
您可以使用onError选项来处理错误:
app.post('/upload',[
  multer({
    dest    : './uploads/',
    onError : function(err, next) {
      console.log('error', err);
      next(err);
    }
  }),
  function(req, res) {
    res.status(204).end();
  }
]);

如果您调用 next(err),您的路由处理程序(生成 204 响应)将被跳过,并且错误将由 Express 处理。

我认为(不确定因为它取决于 multer 的实现方式),当文件保存时,您的路由处理程序将被调用。您可以使用onFileUploadComplete在上传完成时记录消息,并将其与调用路由处理程序的时间进行比较。

从代码来看,multer 在文件完全上传后调用下一个中间件/路由处理程序。


36
onError在Multer 1.0.0中已被移除。 - Jake Wilson
1
我找到了一个使用新的multer版本的可工作代码:https://github.com/expressjs/multer/issues/336#issuecomment-242906859 - Van Tho
onError 的替代方案是什么? - mercury
1
@HosMercury https://github.com/expressjs/multer#error-handling - robertklep
如何处理如果 multer 上传成功但路由处理程序失败的情况? - m9m9m
@m9m9m 这将取决于路由处理程序的实现方式,以及您所指的具体处理方式。 - robertklep

8

1
如下代码所示(来自muter index.js文件的源代码),如果您没有传递onError回调函数,则错误将由express处理。
    fileStream.on('error', function(error) {
      // trigger "file error" event
      if (options.onError) { options.onError(error, next); }
      else next(error);
    });

1
    var multer = require('multer')
    var upload = multer().single('avatar')
     
    app.post('/profile', function (req, res) {
      upload(req, res, function (err) {
        if (err instanceof multer.MulterError) {
          handle error
        } else if (err) {
          handle error
        }
        else{
          write you code
        }
      })
    })

你可以从文档中看到这个。

1
根据 multer 文档 (https://github.com/expressjs/multer#error-handling)

错误处理

当遇到错误时,Multer 会将错误委托给 Express。您可以使用标准的 express 方法显示一个漂亮的错误页面。

如果您想要专门捕获 Multer 的错误,您可以自己调用中间件函数。 此外,如果您只想捕获 Multer 错误,您可以使用附加到 multer 对象本身的 MulterError 类 (例如 err instanceof multer.MulterError)。

code sample

   const multer = require('multer')
   const upload = multer().single('avatar')
   
   app.post('/profile', function (req, res) {
     upload(req, res, function (err) {
       if (err instanceof multer.MulterError) {
         // A Multer error occurred when uploading.
       } else if (err) {
         // An unknown error occurred when uploading.
       }
   
       // Everything went fine.
     })
   })

当我们使用最新版本的multer(v1.4.5-lts.1)重新编写此问题的代码时

const express = require('express');

const multer = require('multer');

const app = express();

const upload = multer({ dest: './uploads/' }).single('fieldName');

app.get('/', (req, res) => {
    res.send('hello world');
});

app.post(
    '/upload',
    (req, res, next) => {
        upload(req, res, (err) => {
            if (err instanceof multer.MulterError) {
                res.status(404).send(err + 'Upload failed due to multer error');
            } else if (err) {
                res.status(404).send(err + 'Upload failed due to unknown error');
            }
            // Everything went fine.
            next();
        });
    },
    (req, res) => {
        res.status(204).end();
    }
);

app.listen(3000);

为了检查Multer错误和非Multer错误,我们可以使用fileFilter和limits添加验证。 例如: 我正在添加一个CSV文件过滤方法和一些限制

// CSV file filter - will only accept files with .csv extension
const csvFilter = (req, file, cb) => {
    console.log('csv filter working');
    if (file.mimetype.includes('csv')) {
        cb(null, true);
    } else {
        cb('Please upload only csv file.', false);
    }
};

// adding the csv file checking, file number limit to 1 and file size limit 10 1kb
const upload = multer({
    dest: './uploads/',
    fileFilter: csvFilter,
    limits: { files: 1, fileSize: 1024 } 
}).single('fieldName');

当我们试图上传非CSV文件或大小超过1kb的文件或多个文件时,会出现不同的错误。


1

当用户向您发送任何内容时,请小心处理系统。

我通常设置更多 [*选项1]:

process.on('uncaughtException', function(ls){
  // console.log(ls);
  (function(){})();
});

然后:

var upload= multer({ dest: __dirname + '/../uploads/' }).single('photos');
// middle ..
upload(req, res, function (err) {
  if (err instanceof multer.MulterError) {
    // A Multer error occurred when uploading.
    console.log('MulterError', err);
  } else if (err) {
    // An unknown error occurred when uploading.
    // Work best when have [*option1]
    console.log('UnhandledError', err);
  }
  if(err) {
    return res.sendStatus(403);
  }
  res.sendStatus(200);
});

包名: "multer": "^1.4.2"


0

我知道现在已经很晚了,但这可能会帮助其他人。

以下是我如何处理错误并在我的 express/typescript 项目中安全使用它的方法。

const upload = (fieldName: string) => {
  return (req: Request, res: Response, next: NextFunction) => {
    return multer({
      storage: multer.diskStorage({
        destination: (req, file, cb) => {
          if (file.fieldname === 'post') {
            return cb(null, `${path.join(path.dirname(__dirname), 'uploads/postImg')}`);
          } else if (file.fieldname === 'profile') {
            return cb(null, `${path.join(path.dirname(__dirname), 'uploads/ProfilePic')}`);
          } else {
            return cb(new Error(`${file.fieldname} is incorrect`), null);
          }
        },
        filename: (req, file, cb) => {
          return cb(null, `${file.originalname}-${Date.now()}-${file.fieldname}`);
        },
      }),
      fileFilter: (req, file, cb) => {
        const fileExtension = file.mimetype.split('/')[1];
        if (!(fileExtension in allowedFiles)) return cb(null, false);
        return cb(null, true);
      },
      dest: `${path.join(path.dirname(__dirname), 'uploads')}`,
      limits: {
        fileSize: 1024 * 1024 * 3, // 3MB
        files: 1,
      },
    }).single(fieldName)(req, res, (err: any) => {
      if (err instanceof multer.MulterError) {
        // handle file size error
        if (err.code === 'LIMIT_FILE_SIZE') return res.status(400).send({ error: err.message });
        // handle unexpected file error
        if (err.code === 'LIMIT_UNEXPECTED_FILE') return res.status(400).send({ error: err.message });
        // handle unexpected field key error
        if (err.code === 'LIMIT_FIELD_KEY') return res.status(400).send({ error: err.message });
      }
      next();
    });
  };
};




app.post("/upload", (req: Request, res:Response)=>{
res.json({message:"file uploaded"})
})

0
我认为处理错误的最佳方式是使用中间件。
const multerErrorHandling = (err, req, res, next) => {
if (err instanceof multer.MulterError) {
  res.status(400).send("Multer error: " + err.message);
} else {
  next();
}
};
  // you should use after multer to send another respond.
  app.post("/upload", singleUpload,multerErrorHandling,(req, res) => {

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接