我正在尝试在服务器中上传图片。在前端,我正在使用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没有处理该文件。在客户端,我得到:完成。
所以我做错了什么?我如何使它与这种后端结构一起使用?
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中间件配置系统的非常灵活的特性。