Как получить тело из HttpErrorResponse в Angular 6? - PullRequest
0 голосов
/ 13 декабря 2018

Я создал вызов REST API в своем приложении Angular, которое загружает файл.

Я устанавливаю responseType в значение 'blob', так как я ожидаю файл в ответ.

Но когдана сервере нет доступных файлов. Ответ имеет код ошибки 404, т. е. неверный запрос с некоторым сообщением в теле.

Но я не могу разобрать это сообщение об ошибке из тела, поскольку HttpErrorResponse предоставляет объект BLOB-объектаin error.error

Как получить фактическое тело из объекта ошибки вместо blob.

Также есть ли способ настроить angular, чтобы при успешном вызове API анализировать запрос виначе blob разберет его в json ???

Надеясь на разрешение

Ответы [ 3 ]

0 голосов
/ 13 декабря 2018

Параметр: {наблюдать: 'ответ'} , позволяет прочитать полный ответ, включая заголовки.См. Описание ниже: -

Скажите HttpClient, что вы хотите получить полный ответ с параметром наблюдения:

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

Теперь HttpClient.get () возвращает Observable типизированного HttpResponse, а не простоДанные 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 };
    });

и получение такого сообщения об ошибке: -

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

import {catchError} из 'rxjs / operator';

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

Ссылка: https://angular.io/guide/http: чтение полного ответа

Измените свой код соответствующим образом.

0 голосов
/ 13 декабря 2018

Если возвращаемый ContentType отличается, вы можете использовать его для определения, является ли это правильный двоичный файл или текст в двоичном формате.

позволяет рассмотреть два файла: службу, которая обрабатывает ваш запрос икомпонент, который выполняет бизнес-логику

Внутри вашего сервиса, ваш метод загрузки, например:

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

В вашем компоненте

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

Если вы хотите, вы можетевсе внутри самого компонента.

0 голосов
/ 13 декабря 2018

Вы можете попробовать отдельную функцию обработчика ошибок, которая возвращает ответ как T следующим образом -

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

Затем просто используйте его для отслеживания ошибок в вашем запросе следующим образом-

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

К вашему сведению, функция extractFiles, которую я использовал выше для возврата файла, выглядит следующим образом -

public extractFiles(res: Blob): Blob{
    return res;
}
...