gpt4 book ai didi

node.js - 在 Angular 中上传文件 - 显示在 req.body 中,而不是 Nodejs 服务器的 req.files 中

转载 作者:太空宇宙 更新时间:2023-11-03 23:58:25 29 4
gpt4 key购买 nike

在我使用 multer 作为中间件的 Nodejs api 中,我可以在 request.file 属性中看到 postman 发布文件请求,当然,该属性随后会保存在我的服务器上。该请求以内容类型表单数据发送。一旦在我的 Controller 上点击“保存”,文件就已经上传。文件的所有详细信息都在 request.files 属性中

在 Angular 中,附加文件被添加到请求正文中,而我的 Nodejs 应用程序无法保存该文件,因为中间件看不到它。图像数据以 Base64 编码字符串形式出现

我尝试将 Angular 中的标题设置为 multipart/form-data,但收到 500 错误“Multipart:未找到边界”。

在 Postman 中,如果我删除表单数据并将其设置为无,它也不起作用

Angular 分量

  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);
});
}

Angular 服务

  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 设置

 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;

要保存的 Controller

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
});
}

}

我希望 Angular 文件上传的工作方式与 postman 示例完全相同。我不介意在 Controller 中调用 save 后立即写入文件,因为我可以向中间件添加验证。如果有人对此有任何想法,我将不胜感激

示例 Angular 发送请求 enter image description here

谢谢

//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);
});
}

最佳答案

我可以建议 Multer 的替代方案吗?

请参阅下面的每周 npm 下载量:

multer: 466,964

formidable: 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' })
});
})

Angular 模板:

<input type="file" (change)="onFileInput($event)" placeholder="Upload file" accept=".JPG,.pdf,.doc,.docx">

Angular 分量:

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)
)

}

关于node.js - 在 Angular 中上传文件 - 显示在 req.body 中,而不是 Nodejs 服务器的 req.files 中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55929074/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com