在使用multer作为中间件的nodejs api中,我可以在request.file属性中看到邮递员发布文件的请求,然后将其保存在服务器上。请求以内容类型form-data发送。在我的控制器上点击“保存”后,该文件已经上传。文件的所有详细信息都在request.files属性中
在Angular中,附件已添加到请求的正文中,而我的nodejs应用程序无法保存该文件,因为中间件看不到它。 imagedata作为base64编码的字符串
我尝试将标题中的标题设置为multipart / form-data,但出现500错误“ Multipart:Boundary not found”。
在邮递员中,如果我删除表单数据并设置为无,则它也不起作用
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});
}
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
});
}
}
我希望角度文件上传的工作方式与邮递员示例完全相同。我不介意在调用保存到控制器后立即写入文件,因为我可以向中间件添加验证。如果有人对此有任何想法,我将不胜感激
谢谢
//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);
});
}
答案 0 :(得分:1)
我可以建议替代Multer吗?
请参阅下面的每周npm下载:
乘积:466,964
可塑:2,116,997
nodejs服务器:
app.post('/upload', (req, res) => {
var form = new formidable.IncomingForm()
form.parse(req)
form.on('fileBegin', function (name, file) {
var path = __dirname + '/uploads'
if (!fs.existsSync(path)) {
fs.mkdirSync(path)
}
file.path = __dirname + '/uploads/' + file.name;
});
form.on('file', function (name, file) {
console.log('Uploaded ' + file.name);
res.send({ message: 'uploaded' })
});
})
角度模板:
<input type="file" (change)="onFileInput($event)" placeholder="Upload file" accept=".JPG,.pdf,.doc,.docx">
角组件:
onFileInput(event) {
let fileList: FileList = event.target.files;
let file = fileList[0]
console.log(file);
let formData: FormData = new FormData();
formData.append('uploadFile', file, file.name);
this.http.post('http://localhost:3001/upload', formData).subscribe(
res => console.log(res)
)
}