В приложении стека MEAN мне нужно отправить FormData
(с файлом) на внутренний сервер и сохранить эту информацию соответственно в MongoDB
. Вот Angular
метод компонента, который передает Form
-
saveProduct(formDirective): void {
let formData: FormData = new FormData();
formData.append("name", formModel.nameFormControl as string);
formData.append("price", formModel.priceFormControl as string);
formData.append("currency", formModel.currencyFormControl as string);
formData.append("url", formModel.urlFormControl as string);
formData.append("description", formModel.descriptionFormControl as string);
if (this.fileToUpload !== null) {
formData.append("uploadFile", this.fileToUpload, this.fileToUpload.name);
}
let headers = new Headers();
headers.append("Content-Type", "multipart/form-data");
headers.append("Accept", "application/json");
headers.append("Authorization", this.jwtToken);
this.productsService.addProduct(formData, headers).subscribe(res => {.......});
}
handleFileInput(files: FileList) {
if (files.length > 0) {
this.fileToUpload = files.item(0);
}
}
Вот Component
HTML для файла формы, где File
информация идеально добавляется в FormData
. Это проверено и проверено -
<input
#file
formControlName="imageFormControl"
id="file"
type="file"
accept="image/x-png,image/gif,image/jpeg"
(change)="handleFileInput($event.target.files)"
/>
Вот Service
метод, который отправляет FormData
в API -
addProduct(formData: FormData, headers: any): any {
formData.forEach(entries => console.log(entries));
return this.http
.post(environment.apiURL + "/admin/product/save", formData, headers)
.map(res => res);
}
В console
Я получаю FormData
сFile
информация.
Перейдем к Express API, где у меня возникла проблема
Я создал маршрут API в Angular SSR (сервер.ts). Вот как маршрут API добавляется в файл server.ts
-
import { routes } from './api/routes';
app.use('/api', routes);
Структура файлов API имеет следующую иерархию -
api---
---functions
admin.functions.ts
---routes
admin.routes.ts
---routes.ts
Вот мой файл routes.ts
-
import { Router } from 'express';
import AdminRoutes from './routes/admin.route';
export const routes = new Router();
// ADMIN ROUTES
routes.use('/admin', AdminRoutes);
export default routes;
Вот routes/admin.routes.ts
код -
import {
Router,
} from 'express';
import AdminAPI from '../functions/admin.functions';
const routes = new Router();
routes.route('/product/save').post(AdminAPI.saveProduct);
export default routes;
Вот functions/admin.functions.ts
код -
import axios from 'axios';
class AdminAPI {
async saveProduct(req, res, next) {
try {
console.log('admin save bot', `${SERVER}/admin/product/save`);
console.log('body', req.body); <- Here I expected FormData
const response = await axios.post(`${SERVER}/admin/product/save`, req.body, {headers: req.headers});
res.json(response.data);
} catch (error) {
next(error);
}
}
}
export default new AdminAPI();
Здесь req.body пусто. То, что я ожидал в req.body
, у меня будет FormData
, но я не получу. Мне нужно отправить FormData
информацию в бэкэнд через Axios
Для справки, давайте перейдем к серверному коду, который прекрасно работает, когда я не использую Angular SSR
exports.admin_save_default_product = function(req, res, next) {
req.pipe(req.busboy);
var product = {};
req.busboy.on("field", function(key, value, keyTruncated, valueTruncated) {
product[key] = value;
});
req.busboy.on("file", function(fieldname, file, filename) {
let file_type = filename.split(".").pop();
if (
file_type === "png" ||
file_type === "gif" ||
file_type === "jpeg" ||
file_type === "jpg"
) {
let file_stream;
let new_filename = Date.now() + "." + file_type;
let filePath = path.join(__basedir, "/server/images", new_filename);
fileUploaded = true;
product.image = new_filename;
file_stream = fs.createWriteStream(filePath);
file.pipe(file_stream);
file_stream.on("close", function() {
console.log("file uploaded!");
});
}
});
req.busboy.on("finish", function() {
let timestamp = new Date();
let current_user_id = req._id;
let current_user_promise = userModel.find_user_by_id(current_user_id);
current_user_promise
.then(function(result) {
product.author = result;
product.source = process.env.PRODUCT_DEFAULT_SOURCE;
product.created_time = timestamp;
product.bot_enabled = 0;
let save_product_promise = productModel.save_product(product);
save_product_promise
.then(function(result) {
var response_information = {
message: "success"
};
res.status(201).json(response_information);
})
.catch(function(err) {
res.status(500).json({ error: err });
});
})
.catch(function(err) {
res.status(500).json({ error: err });
});
});
};
Здесь busboy file and field
события не работают, так как field
и file
пусты. Но finish
событие работает нормально.
Итак, главная проблема, с которой я сталкиваюсь - не может правильно выполнить запрос Axios POST
, который может отправить FormData
в бэкэнд
Заранее спасибо!