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

问题描述 投票:0回答:1

我正在尝试在服务器中上传图片。在前端,我正在使用Angular。前端工作正常,我只是发布了一下以向您展示如何将文件传递给后端!

component.html

<div fxLayout="column" fxLayoutAlign="center center">
  <div>
    <mat-form-field>
      <ngx-mat-file-input placeholder="Only photos" [accept]="'.jpg, .jpeg, .png'" (change)="onChange($event)"></ngx-mat-file-input>
    </mat-form-field>
  </div>
  <div>
    <button mat-button (click)="onSubmit()">Send</button>
  </div>
</div>

component.ts-函数

  imagem: File;

  constructor(private uploadService: UploadService) { }

  onChange(event) {
    this.imagem = event.target.files[0];
  }
  onSubmit() {
    this.uploadService.upload(this.imagem);
  }

upload.service.ts-功能

  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

const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');

const rtsIndex = require('./routes/index.router');

var app = express();

// middleware
app.use(bodyParser.json());
app.use(cors());
app.use('/api', rtsIndex);

// start server
app.listen(3000, () => console.log('Port: 3000'));

index.router.js

const express = require('express');
const router = express.Router();

const ctrlUpload = require('../controllers/upload.controller');

router.post('/upload', ctrlUpload.send);

module.exports = router;

upload.controller.js

const express = require('express');
const multer = require('multer');

const storage = multer.diskStorage({
    destination: (req, file, cb) => {
        cb(null, 'uploads/');
    },
    filename: (req, file, cb) => {
        cb(null, Date.now()+'-'+file.originalname);
    }
});

const upload = multer({ storage });

module.exports.send = (req, res) => {
  upload.single('img');
  console.log(req.body, req.files);
  res.send('ok');
}

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

所以我做错了什么?我如何使它与这种后端结构一起使用?

node.js mean-stack image-uploading multer
1个回答
0
投票

Express中间件被设计为在路由级别安装。实际上,在MVC模型中,快速程序员将控制器称为“路由”(我个人更喜欢将其称为控制器而不是代码中的路由)。从传统的MVC框架来看,将控制器与路由分开(它们都意味着相同的意思)并没有多大意义-但是您可以,如果需要的话。

要使用multer 按设计要求

,您需要在index.router.js中执行此操作:

index.router.js

const express = require('express');
const router = express.Router();
const multer = require('multer');

const ctrlUpload = require('../controllers/upload.controller');

const storage = multer.diskStorage({
    destination: (req, file, cb) => {
        cb(null, 'uploads/');
    },
    filename: (req, file, cb) => {
        cb(null, Date.now()+'-'+file.originalname);
    }
});

const upload = multer({ storage });

router.post('/upload', upload.single('img'), ctrlUpload.send);

module.exports = router;

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


但是您可以在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中实现中间件,这是您需要做的:

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
}

但是这是非常不标准的,对于经验丰富的Express.js程序员来说是非常出乎意料的。即使有可能,我也不会这样做。它还将中间件与控制器紧密耦合在一起,从而完全消除了Express中间件配置系统的非常灵活的特性。

© www.soinside.com 2019 - 2024. All rights reserved.