web-dev-qa-db-fra.com

Télécharger une image avec HttpClient

Problème

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.

Voici ce que j'ai essayé jusqu'à présent:

model.service.ts

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

avatar-uploader.component.ts

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.

24
mrkvon

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)}
    )
  }
21
robert king

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