Node.js 如何在nodejs的控制器内调用multer中间件?

Node.js 如何在nodejs的控制器内调用multer中间件?,node.js,mean-stack,image-uploading,multer,Node.js,Mean Stack,Image Uploading,Multer,我正在尝试在我的服务器中上载图像。 在前端,我与Angular合作。 前端工作正常,我只是想告诉你我是如何将文件传递到后端的 component.html upload.service.ts-功能 imagem: File; constructor(private uploadService: UploadService) { } onChange(event) { this.imagem = event.target.files[0]; } onSubmit()

我正在尝试在我的服务器中上载图像。 在前端,我与Angular合作。 前端工作正常,我只是想告诉你我是如何将文件传递到后端的

component.html

upload.service.ts-功能

  imagem: File;

  constructor(private uploadService: UploadService) { }

  onChange(event) {
    this.imagem = event.target.files[0];
  }
  onSubmit() {
    this.uploadService.upload(this.imagem);
  }
  constructor(private http: HttpClient) { }

  upload(file: File) {
    const formData = new FormData();
    formData.append('img', file, file.name);
    this.http.post(environment.apiBaseUrl + '/upload', formData, {responseType: 'text'}).subscribe(
      res => console.log('Done')
    );
  }
在后端,我有以下结构:

app.js

index.router.js

upload.controller.js

我尝试调用路由中的中间件,但我认为它不正确,也没有达到目标。Algo,上传不是一个。 在服务器端,我得到:{}未定义作为结果,这可能意味着multer没有处理该文件。 在客户端,我完成了


那么我做错了什么?我如何才能使它与这种后端结构一起工作?

Express Middleware设计为在路由级别安装。事实上,在MVC模型中,express程序员亲自调用控制器路由,而不是在代码中调用路由。从传统的MVC框架来看,将控制器和路由分开它们都意味着同一件事没有意义,但是如果你愿意,你可以这样做

要按设计使用multer,您需要在index.router.js中执行此操作:

index.router.js

然后需要从upload.controller.js中删除所有与multer相关的代码

但是,您可以坚持在upload.controller.js中执行此操作。这里的关键是理解什么是中间产品

在Express中,中间件是具有以下原型的函数:

function (req, res, next) { // next is optional
    // middleware logic
}
是的,没错。upload.controller.js文件中的代码是一个中间件。您自己编写的中间件恰好位于中间件链的末端

你看,Express只接受中间产品。快车没有别的了。路线是恰好在终点的中间产品

Express.use、.get、.post和相关方法接受无限多个参数。第一个参数是可选的路由说明符,但不是必需的,其余参数是中间件。例如:

app.get('/foo',
  (req, res, next) => {
    // first middleware
    next(); // next is what allows processing to continue
  },
  (req, res, next) => {
    // second middleware
    next();
  },
  (req, res, next) => {
    res.send('hello'); // controller logic - a controller
                       // is just the last middleware

    // Note: if you call next() instead of res.send() in a 
    // controller express will respond with a 500 internal 
    // server error status with whatever string you pass
    // to next() as the error message.
  }
);
知道了这一点,我们知道upload.single'img'函数返回什么。该函数不执行中间件逻辑。相反,它返回中间件函数:

let middleware = upload.single('img');

// middleware is now a function with the prototype:
// (req, res, next) => {}
因此,要执行中间件逻辑,我们必须将其称为express,它会自动将其作为路由处理的一部分进行调用,就像它如何调用控制器功能一样,但如果我们想自己执行,我们可以

如果要在upload.controller.js中实现中间件,需要执行以下操作:

那东西太多了。如果我们稍微重构一下代码,就可以使代码更容易理解:

let middleware = upload.single('img');

module.exports.send = (req, res, next) => {
  // Define the controller here to capture
  // req and res in a closure:
  let controller = () => {
      console.log(req.body, req.files);
      res.send('ok');
  };

  middleware(req, res, controller); // call the middleware with
                                    // our controller as callback
}

但是这是非常不标准的,对于一个经验丰富的Express.js程序员来说是非常意外的。即使有可能,我也不会这么做。它还将中间件与控制器紧密耦合,完全否定了Express中间件配置系统的灵活性。

Express中间件旨在安装在路由级别。事实上,在MVC模型中,express程序员亲自调用控制器路由,而不是在代码中调用路由。从传统的MVC框架来看,将控制器和路由分开它们都意味着同一件事没有意义,但是如果你愿意,你可以这样做

要按设计使用multer,您需要在index.router.js中执行此操作:

index.router.js

然后需要从upload.controller.js中删除所有与multer相关的代码

但是,您可以坚持在upload.controller.js中执行此操作。这里的关键是理解什么是中间产品

在Express中,中间件是具有以下原型的函数:

function (req, res, next) { // next is optional
    // middleware logic
}
是的,没错。upload.controller.js文件中的代码是一个中间件。您自己编写的中间件恰好位于中间件链的末端

你看,Express只接受中间产品。快车没有别的了。路线是恰好在终点的中间产品

Express.use、.get、.post和相关方法接受无限多个参数。第一个参数是可选的路由说明符,但不是必需的,其余参数是中间件。例如:

app.get('/foo',
  (req, res, next) => {
    // first middleware
    next(); // next is what allows processing to continue
  },
  (req, res, next) => {
    // second middleware
    next();
  },
  (req, res, next) => {
    res.send('hello'); // controller logic - a controller
                       // is just the last middleware

    // Note: if you call next() instead of res.send() in a 
    // controller express will respond with a 500 internal 
    // server error status with whatever string you pass
    // to next() as the error message.
  }
);
知道了这一点,我们知道upload.single'img'函数返回什么。该函数不执行中间件逻辑。相反,它返回中间件函数:

let middleware = upload.single('img');

// middleware is now a function with the prototype:
// (req, res, next) => {}
因此,要执行中间件逻辑,我们必须将其称为express,它会自动将其作为路由处理的一部分进行调用,就像它如何调用控制器功能一样,但如果我们想自己执行,我们可以

如果要在upload.controller.js中实现中间件,需要执行以下操作:

那东西太多了。如果我们稍微重构一下代码,就可以使代码更容易理解:

let middleware = upload.single('img');

module.exports.send = (req, res, next) => {
  // Define the controller here to capture
  // req and res in a closure:
  let controller = () => {
      console.log(req.body, req.files);
      res.send('ok');
  };

  middleware(req, res, controller); // call the middleware with
                                    // our controller as callback
}
但是这是非常不标准的,对于一个经验丰富的Express.js程序员来说是非常意外的。即使有可能,我也不会这么做。它还与中间件紧密耦合
您的控制器完全否定了Express中间件配置系统非常灵活的特性。

一个基于@slebetman答案的Multer中间件分离文件的示例

/middleware/multer.js

这样可以避免错误文件类型的状态为500
希望这对某人有所帮助:D

一个基于@slebetman答案的Multer中间件分离文件的示例

/middleware/multer.js

这样可以避免错误文件类型的状态为500 希望这对某人有帮助:D

module.exports.send = (req, res, next) => {
  upload.single('img')(req, res, () => {
      // Remember, the middleware will call it's next function
      // so we can inject our controller manually as the next()

      console.log(req.body, req.files);
      res.send('ok');
  });
}
let middleware = upload.single('img');

module.exports.send = (req, res, next) => {
  // Define the controller here to capture
  // req and res in a closure:
  let controller = () => {
      console.log(req.body, req.files);
      res.send('ok');
  };

  middleware(req, res, controller); // call the middleware with
                                    // our controller as callback
}
const multer = require('multer')
const ErrorMessages = require('../constants/ErrorMessages')

function makeid (length) {
  var result = ''
  var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
  var charactersLength = characters.length
  for (var i = 0; i < length; i++) {
    result += characters.charAt(Math.floor(Math.random() * charactersLength))
  }
  return result
}

const DIR = './uploads/'
const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, DIR)
  },
  filename: (req, file, cb) => {
    const fileName = file.originalname.toLowerCase().split(' ').join('-')
    cb(null, makeid(16) + '_' + fileName)
  }
})
const upload = multer({
  storage: storage,
  fileFilter: (req, file, cb) => {
    if (file.mimetype === 'image/png' || file.mimetype === 'application/pdf') {
      cb(null, true)
    } else {
      cb(null, false)
      return cb(new Error('Only .png, .jpg, .mp4 and .jpeg format allowed!'))
    }
  }
})

module.exports.send = (req, res, next) => {
  return upload.single('file')(req, res, () => {
    // Remember, the middleware will call it's next function
    // so we can inject our controller manually as the next()

    if (!req.file) return res.json({ error: ErrorMessages.invalidFiletype })
    next()
  })
}
routes.post('/object', multer.send, ObjectController.createObject)