如何在nodejs的控制器中调用multer中间件?
How to call multer middleware inside a controller in nodejs?
我正在尝试在我的服务器中上传图片。
在前端,我正在使用 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');
}
我试过调用路由里面的中间件,但是觉得不对,没有达到目的。 Algo,上传的不是一个。
在服务器端,我得到:{} undefined 作为结果,这可能意味着 multer 没有处理文件。
在客户端,我得到:完成。
那我做错了什么?我怎样才能让它与这个后端结构一起工作?
Express 中间件旨在安装在路由级别。事实上,在 MVC 模型中,express 程序员调用控制器 "routes"(我个人更喜欢在我的代码中称它们为控制器而不是路由)。从传统的 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')
returns是什么功能了。 函数不执行中间件逻辑。相反,它 returns 中间件函数:
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 中间件配置系统非常灵活的特性。
基于 @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
如何在 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);
}
});
},
};
我正在尝试在我的服务器中上传图片。 在前端,我正在使用 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');
}
我试过调用路由里面的中间件,但是觉得不对,没有达到目的。 Algo,上传的不是一个。 在服务器端,我得到:{} undefined 作为结果,这可能意味着 multer 没有处理文件。 在客户端,我得到:完成。
那我做错了什么?我怎样才能让它与这个后端结构一起工作?
Express 中间件旨在安装在路由级别。事实上,在 MVC 模型中,express 程序员调用控制器 "routes"(我个人更喜欢在我的代码中称它们为控制器而不是路由)。从传统的 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')
returns是什么功能了。 函数不执行中间件逻辑。相反,它 returns 中间件函数:
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 中间件配置系统非常灵活的特性。
基于 @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
如何在 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);
}
});
},
};