web-dev-qa-db-fra.com

Comment obtenir le corps de HttpErrorResponse dans Angular 6?

J'ai créé un REST appel API dans mon Angular app qui télécharge un fichier.

Je mets responseType sur 'blob' car j'attends un fichier en réponse.

Mais quand aucun fichier n'est disponible sur le serveur, la réponse a un code d'erreur 404, c'est-à-dire une mauvaise demande avec un message dans le corps.

Mais je ne suis pas en mesure d'analyser ce message d'erreur du corps car HttpErrorResponse donne un objet blob dans error.error

Comment puis-je obtenir le corps réel de l'objet d'erreur au lieu de blob.

Existe-t-il également un moyen de configurer angular qui, en cas de succès d'un appel api, analyse la demande en blob, sinon l'analyser en json ???

En espérant une résolution

4
Nitish Kumar

Si le ContentType retourné est différent, vous pouvez l'utiliser pour distinguer s'il s'agit d'un fichier binaire correct ou d'un texte au format binaire.

considérons que vous avez deux fichiers, un service, qui gère votre demande et un composant qui fait la logique métier

Dans votre service, ayez votre méthode de téléchargement comme:

 public downloadFile(yourParams): Observable<yourType | Blob> {
        return this._http.post(yourRequestURL, yourParams.body, {responseType: 'blob'}).pipe(
            switchMap((data: Blob) => {
                if (data.type == <ResponseType> 'application/octet-stream') {
                    // this is a correct binary data, great return as it is
                    return of(data);
                } else {
                    // this is some error message, returned as a blob
                    let reader = new FileReader();
                    reader.readAsBinaryString(data);  // read that message
                    return fromEvent(reader, 'loadend').pipe(
                        map(() => {
                            return JSON.parse(reader.result); // parse it as it's a text.
                            // considering you are handling JSON data in your app, if not then return as it is
                        })
                    );
                }
            })
        );
}

Dans votre composant

 public downloadFile(params): void {
        this._service.downloadFile(params)
            subscribe((data: yourType | Blob) => {
                if (data instanceof Blob) {
                    fileSaverSave(data, filename);  // use fileSaver or however you are downloading the content
                    // add an import for saveAs (import { saveAs as fileSaverSave } from 'file-saver';)
                } else {
                    // do your componnet logic to show the errors
                }
            })    
    }

Si vous le souhaitez, vous pouvez tout avoir à l'intérieur de votre composant lui-même.

1
xyz

Paramètre: {observez: 'réponse'} , vous permet de lire la réponse complète, y compris les en-têtes. Voir la description ci-dessous: -

Dites à HttpClient que vous voulez la réponse complète avec l'option observe:

getConfigResponse(): Observable<HttpResponse<Config>> {
    return this.http.get<Config>(this.configUrl, { observe: 'response' });
}

Maintenant, HttpClient.get () renvoie un Observable de HttpResponse typé plutôt que juste les données JSON.

this.configService.getConfigResponse()
    // resp is of type `HttpResponse<Config>`
    .subscribe(resp => {
        // display its headers
        const keys = resp.headers.keys();
        this.headers = keys.map(key =>
            `${key}: ${resp.headers.get(key)}`);

        // access the body directly, which is typed as `Config`.
        this.config = { ...resp.body };
    });

et obtenir le corps d'erreur comme ça: -

private handleError(error: HttpErrorResponse) {
  if (error.error instanceof ErrorEvent) {
    // A client-side or network error occurred. Handle it accordingly.
    console.error('An error occurred:', error.error.message);
  } else {
    // The backend returned an unsuccessful response code.
    // The response body may contain clues as to what went wrong,
    console.error(
      `Backend returned code ${error.status}, ` +
      `body was: ${error.error}`);
  }
  // return an observable with a user-facing error message
  return throwError(
    'Something bad happened; please try again later.');
};

importer {catchError} depuis 'rxjs/operators';

getConfig() { return this.http.get<Config>(this.configUrl) .pipe( catchError(this.handleError) ); }

Référence: https://angular.io/guide/http : lecture de la réponse complète

Modifiez votre code en conséquence.

1
Gourishankar

Vous pouvez essayer une fonction de gestionnaire d'erreurs distincte, qui renvoie la réponse sous la forme T comme suit -

public handleError<T>(operation = 'operation', result?: T) {
    return (error: any): Observable<T> => {

        // TODO: send the error to remote logging infrastructure
        console.error(error); // log to console instead

        // TODO: better job of transforming error for user consumption
        console.log(`${operation} failed: ${error.message}`);

        // Let the app keep running by returning an empty result.
        return of(result as T);
    };
}

Ensuite, utilisez-le simplement pour suivre les erreurs dans votre demande comme suit -

return this.http.post(this.appconstants.downloadUrl, data, { responseType: 'blob' }).pipe(
    map(this.loggerService.extractFiles),
    catchError(this.loggerService.handleError<any>('downloadFile'))    // <----
);

Pour info, la fonction extractFiles que j'ai utilisée ci-dessus pour renvoyer un fichier est la suivante -

public extractFiles(res: Blob): Blob{
    return res;
}
0
Tushar Walzade

Pour les futurs visiteurs (puisque le titre est générique):

Si le backend renvoie JSON en cas d'erreur (idéalement, en suivant RFC 7807 , ce qui signifierait également le type de contenu application/problem+json), Le error.error est un objet JSON, pas une chaîne . Ainsi, pour l'imprimer, par exemple, vous devez d'abord le filtrer:

console.error(
  `Backend returned code ${error.status}, ` +
  `body was: ${JSON.stringify(error.error)}`);

Je pense que la confusion vient de l'officiel Angular documentation , qui contient cette déclaration:

// The backend returned an unsuccessful response code.
// The response body may contain clues as to what went wrong,
console.error(
  `Backend returned code ${error.status}, ` +
  `body was: ${error.error}`);

Mais avec error.error Étant un objet JSON (dans les cas standard), vous obtenez [object Object] Imprimé pour le corps au lieu de la représentation sous forme de chaîne de cet objet JSON. Même sortie inutile si vous essayez ${error.error.toString()}.

0
Voicu