J'essaie de télécharger une image avec angular HttpClient
vers l'API Content-Type: multipart/form-data
(angulaire v4 +). Est-ce pris en charge? Comment faire?
Le téléchargement fonctionne avec XMLHttpRequest
lorsqu’on utilise un module tel que ng2-fancy-image-uploader
. Je préférerais utiliser une méthode personnalisée avec HttpClient
que je pourrais mettre dans un service http avec d'autres méthodes pour accéder à l'API.
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders, HttpResponse } from '@angular/common/http';
import 'rxjs/add/operator/toPromise';
@Injectable()
export class ModelService {
constructor(private http: HttpClient) { }
public async updateAvatar(file: File): Promise<void> {
// headers
const headers = new HttpHeaders()
.append('Content-Type', 'multipart/form-data');
const formData: FormData = new FormData();
formData.append('avatar', file, file.name);
const response: HttpResponse = await this.http
.patch('https://example.com/avatar', formData, { headers, observe: 'response' })
.toPromise();
console.log(response.status);
}
}
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
import { ModelService } from './path/to/model.service';
@Component({
selector: 'app-avatar-uploader',
template: '<input type="file" #fileInput (changes)="uploadAvatar()">'
})
export class AvatarUploaderComponent implements OnInit {
@ViewChild('fileInput') fileInputElement: ElementRef;
constructor() { }
ngOnInit() { }
public async uploadAvatar() {
const file: File = this.fileInputElement.nativeElement.files[0];
await this.model.updateAvatar(file);
}
}
Cette version envoie une requête à l'API (express), mais multer
(une bibliothèque pour analyser multipart/form-data
demandes) ne parvient pas à analyser la demande.
Donc, je suppose que je n’utilise pas le HttpClient
de manière incorrecte, ou ne prend pas en charge multipart/form-data
_ demandes.
J'imagine que l'on pourrait envoyer un fichier encodé en base64 ou utiliser XmlHttpRequest
, mais je pose des questions spécifiques sur la capacité de HttpClient
à le faire.
Pour moi, l’astuce n’était pas de définir le type de contenu sur multipart/form-data. Mais cela a été fait automatiquement pour moi.
<label>
<input type="file" (change)="setFiles($event)" style="display:none" multiple/>
<a mat-raised-button color="primary">
<mat-icon>file_upload</mat-icon>
Select Documents
</a>
</label>
Voici mon code qui télécharge multipart/form-data. Pas besoin de définir les en-têtes.
private setFile(event) {
let files = event.srcElement.files
if (!files) {
return
}
let path = `${environment.celoApiEndpoint}/api/patientFiles`
let data = {"patientData": {
"uid": "",
"firstName": "",
"lastName": "",
"gender": "Not Specified",
"dateOfBirth": ""
}}
// let headers = new HttpHeaders()
// .set('content-type', 'multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW')
// let headers = new HttpHeaders().set('content-type', 'multipart/form-data')
const formData: FormData = new FormData();
for (let i = 0; i < files.length; i++) {
formData.append(i.toString(), files[i], files[i].name);
}
formData.append("data", JSON.stringify(data));
this.http.post(path, formData).subscribe(
(r)=>{console.log('got r', r)}
)
}
Je ne pense pas que le problème vienne d’angular, j’ai utilisé le même code pour envoyer un fichier au serveur (j’utilise Spring dans le backend), la seule différence est que je n’observe pas la requête ni ne convertis la réponse en promesse.
Voir mon code ci-dessous:
let formData: FormData = new FormData();
formData.append('file', this.fileToUpload);
this.http.put(this.usersUrl, formData).subscribe(
data => {
console.log(data);
},
error => {
console.log(error);
}
);