В моем nodejs api, использующем multer в качестве промежуточного программного обеспечения, я вижу запросы файла почты почтальона в свойстве request.file, которое, конечно, затем сохраняется на моем сервере.Запрос отправляется с типом контента form-data.Как только на моем контроллере нажата кнопка «Сохранить», файл уже загружен.Все детали файла (ов) находятся в свойстве request.files
. В Angular прикрепленный файл добавляется в тело запроса, и мое приложение nodejs не может сохранить файл, так как промежуточное ПО не видитЭто.Imagedata приходит как строка в кодировке base64
Я попытался установить заголовки в угловых для multipart / form-data, но я получаю ошибку 500 "Multipart: Граница не найдена".
В Почтальоне, если я удаляю данные формы и задаю значение «Нет», он также не работает
Угловой компонент
imageFile:any;
onImagePicked(imageData: string | File) {
if (typeof imageData === 'string') {
try {
/*this.imageFile = this.sharedService.base64toBlob(
imageData.replace('data:image/jpeg;base64,', ''),
'image/jpeg'
);*/
this.imageFile = imageData;
} catch (error) {
console.log('Err' + error);
return;
}
} else {
this.imageFile = imageData;
}
}
savePhoto() {
console.log ('Save');
this.sharedService.uploadPhoto(this.imageFile).subscribe(val => {
console.log(val);
});
}
Служба углов
public uploadPhoto(image: File) {
//let headers = new HttpHeaders();
//headers = headers.append('Content-Type', 'multipart/form-data');
const imageData = new FormData();
imageData.append('image', image);
return this.httpClient.post(environment.apiURL + this.path, imageData);
//return this.httpClient.post(environment.apiURL + this.path, imageData, {headers: headers});
}
Nodejs Setup
public express: express.Application;
constructor() {
this.express = express();
this.setMiddlewares();
this.setRoutes();
this.catchErrors();
this.setSocketServer();
}
private setMiddlewares(): void {
this.express.options('*', cors());
this.express.use(cors());
this.express.use((reg, res, next) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET, POST, PUT, PATCH, DELETE');
res.setHeader('Access-Control-Allow-Headers', '*');
res.setHeader('Access-Control-Max-Age', 10000);
next();
});
this.express.use(morgan('dev'));
this.express.use(bodyParser.json());
this.express.use(bodyParser.urlencoded({ extended: false }));
this.express.use(helmet());
const storageConfig = multer.diskStorage({
destination: (req, file, callback) => callback(null, './files'),
filename: (req, file, callback) => callback(null, Date.now() + "-" + file.originalname),
});
this.express.use(multer({storage: storageConfig}).any());
}
private setRoutes(): void {
this.express.use('/api', api);
}
Маршрутизатор для фотографий
import { Router } from "express";
import DfrPhotoController from "./dfrphoto.controller";
const dfrPhoto: Router = Router();
const controller = new DfrPhotoController();
dfrPhoto.post('/', controller.save);
export default dfrPhoto;
Контроллер для сохранения
export default class DfrPhotoController {
// TODO: link to the dfr
public save = async (req:Request, res:Response): Promise<any> => {
// Need to see files in request. File is already saved in
let files = req.files;
console.log (files);
if (files === null || files === undefined ) {
res.status(404).send({
success: false,
message:'No Files Found'
});
}
console.log("The file was saved!");
res.status(200).send({
success: true,
message:'Photo saved',
data: files
});
}
}
Я бы хотел, чтобы угловая загрузка файла работала точно так жекстати как пример почтальона.Я не против записи файла, как только я вызову команду save в контроллере, поскольку я могу добавить проверку в промежуточное ПО.Если у кого-то есть идеи по этому поводу, я был бы признателен
Образец угловой отправки запроса 
Спасибо
//Added Component using the image picker (html and ts)
//HTML
<ion-grid>
<form [formGroup]="form" >
<ion-row size="12">
<ion-col size-lg="6" size-xl="6" size="12" size-md="12">
<app-camera (imagePick)="onImagePicked($event)"></app-camera>
<!-- <ion-thumbnail>
<ion-img width="200" height="200" [src]="imageFile" ></ion-img>
</ion-thumbnail>-->
<img [src]="imageFile" >
</ion-col>
<ion-col size-lg="6" size-xl="6" size="12" size-md="12">
<ion-label position="floating">Photo Comments</ion-label>
<!-- <ion-textarea rows="3" formControlName="rigComments"></ion-textarea>-->
<ion-textarea rows="3" formControlName="photoComments"></ion-textarea>
</ion-col>
</ion-row>
<ion-row>
<ion-button (click)="savePhoto()">Save Photo</ion-button>
</ion-row>
</form>
</ion-grid>
//TS
import { Component, OnInit } from '@angular/core';
import { FormControl, Validators, FormGroup } from '@angular/forms';
import { SharedService } from 'src/app/shared/shared.service';
@Component({
selector: 'app-dfr-photo',
templateUrl: './dfr-photo.component.html',
styleUrls: ['./dfr-photo.component.scss'],
})
export class DfrPhotoComponent implements OnInit {
form: FormGroup;
sharedService: SharedService;
constructor(sharedService: SharedService) {
this.sharedService = sharedService;
}
ngOnInit() {
this.form = new FormGroup({
_id: new FormControl(null, {
updateOn: 'blur',
}),
dfrId: new FormControl(null, {
updateOn: 'blur',
validators: [Validators.required]
}),
photoComments: new FormControl(null, {
updateOn: 'blur',
validators: [Validators.required]
}),
image: new FormControl(null, {
updateOn: 'blur'
})
});
}
imageFile:any;
onImagePicked(imageData: string | File) {
if (typeof imageData === 'string') {
try {
/*this.imageFile = this.sharedService.base64toBlob(
imageData.replace('data:image/jpeg;base64,', ''),
'image/jpeg'
);*/
this.imageFile = imageData;
} catch (error) {
console.log('Err' + error);
return;
}
} else {
this.imageFile = imageData;
}
this.form.patchValue({ image: imageData });
this.form.get('image').updateValueAndValidity();
}
savePhoto() {
console.log ('Save');
console.log(this.form.value.image);
this.sharedService.uploadPhoto(this.form.value.image).subscribe(val => {
console.log(val);
});
}
}
// Image Picker Code - JS
import { Component, OnInit, ElementRef, EventEmitter, ViewChild, Output, Input } from '@angular/core';
import { Plugins, CameraResultType, CameraSource, Capacitor} from '@capacitor/core';
import { SafeResourceUrl, DomSanitizer } from '@angular/platform-browser';
import { Platform } from '@ionic/angular';
@Component({
selector: 'app-camera',
templateUrl: './camera.component.html',
styleUrls: ['./camera.component.scss'],
})
export class CameraComponent implements OnInit {
@ViewChild('filePicker') filePickerRef: ElementRef<HTMLInputElement>;
@Output() imagePick = new EventEmitter<string | File>();
@Input() showPreview = false;
selectedImage: string;
usePicker = false;
constructor( private sanitizer: DomSanitizer, private platform: Platform) { }
image2: SafeResourceUrl;
ngOnInit() {
if ( this.platform.is('desktop')) {
this.usePicker = true;
}
}
onPickImage() {
if (!Capacitor.isPluginAvailable('Camera')) {
this.filePickerRef.nativeElement.click();
return;
}
Plugins.Camera.getPhoto({
quality: 50,
source: CameraSource.Prompt,
correctOrientation: true,
width: 300,
resultType: CameraResultType.Base64
})
.then(image => {
const image2: any = image; // to fix access to base64 data
this.selectedImage = image2.base64Data;
this.imagePick.emit(image2.base64Data);
})
.catch(error => {
console.log('ERROR ' + error);
if (this.usePicker) {
this.filePickerRef.nativeElement.click();
}
return false;
});
}
onFileChosen(event: Event) {
const pickedFile = (event.target as HTMLInputElement).files[0];
if (!pickedFile) {
return;
}
const fr = new FileReader();
fr.onload = () => {
const dataUrl = fr.result.toString();
this.selectedImage = dataUrl;
this.imagePick.emit(dataUrl);// (pickedFile);
};
fr.readAsDataURL(pickedFile);
}
}
// Image Picker Code - HTML
<div class="picker">
<ion-button color="primary" (click)="onPickImage()" *ngIf="!usePicker">
<ion-icon name="camera" slot="start"></ion-icon>
<ion-label>Take Picture</ion-label>
</ion-button>
</div>
<input
type="file"
accept="image/jpeg"
*ngIf="usePicker"
#filePicker
(change)="onFileChosen($event)"
/>
// Sidenote - Example of sending directly from the form control (renamed to image)
onImagePicked(imageData: string | File) {
if (typeof imageData === 'string') {
try {
/*this.imageFile = this.sharedService.base64toBlob(
imageData.replace('data:image/jpeg;base64,', ''),
'image/jpeg'
);*/
this.imageFile = imageData;
} catch (error) {
console.log('Err' + error);
return;
}
} else {
this.imageFile = imageData;
}
this.form.patchValue({ image: imageData });
this.form.get('image').updateValueAndValidity();
}
savePhoto() {
this.sharedService.uploadPhoto(this.form.value.image).subscribe(val => {
console.log(val);
});
}