如何在nodejs的控制器内调用multer中间件?
Posted
技术标签:
【中文标题】如何在nodejs的控制器内调用multer中间件?【英文标题】:How to call multer middleware inside a controller in nodejs? 【发布时间】:2020-02-16 20:41:49 【问题描述】:我正在尝试在我的服务器中上传一张图片。 在前端,我正在使用 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');
我尝试调用路由内部的中间件,但我认为它不正确,也没有达到目标。算法,上传不是一个。 在服务器端,我得到: undefined 结果,这可能意味着 multer 没有处理文件。 在客户端我得到:完成。
那么我做错了什么?我怎样才能使它与这个后端结构一起工作?
【问题讨论】:
【参考方案1】: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;
那你需要把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
中实现中间件,你需要这样做:
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 中间件配置系统非常灵活的特性。
【讨论】:
【参考方案2】:一个基于 @slebetman 答案的 Multer 中间件分离文件示例
./middlewares/multer.js
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.js
routes.post('/object', multer.send, ObjectController.createObject)
这避免了错误文件类型的状态 500 希望对某人有所帮助:D
【讨论】:
但重点是存在的。永远不要这样做。按照设计使用的方式使用 Express。不要将控制器逻辑与控制器(路由)分开【参考方案3】:如何在 expressjs 处理程序中使用它的工作示例
import multer from 'multer';
export default
async upload(req: Request, res: Response, next: NextFunction)
const middleware = upload.single('photo');
return middleware(req, res, () =>
try
const file = req.file;
console.log('req.file', req.file);
if (!file)
throw new ResourceValidationError('media-library', [
property: 'avatar',
constraints:
isNotEmpty: 'avatar should not be empty',
,
,
]);
console.log('filename:', file.filename);
res.status(StatusCodes.OK).json(
status: code: StatusCodes.OK, phrase: ReasonPhrases.OK ,
);
catch (error)
next(error);
);
,
;
【讨论】:
以上是关于如何在nodejs的控制器内调用multer中间件?的主要内容,如果未能解决你的问题,请参考以下文章
nodejs--express的中间件multer实现图片文件上传--XUEBIG
nodeJs学习-08 multer中间件,解析post文件,上传文件
使用 multer 和 nodejs 将图像上传到谷歌云存储时出错