Как получить тело из HttpErrorResponse в Angular 6?

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

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

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

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

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

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

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


person Nitish Kumar    schedule 13.12.2018    source источник
comment
вы пробовали {responseType: 'blob' как 'json'}?   -  person Suresh Kumar Ariya    schedule 13.12.2018
comment
Когда вы получаете данные из своего API, если это действительный файл, то что такое responseType, а если это и ошибка, то что такое responseType? Они разные, например: для действительного файла: 'application/octet-stream' и для ошибок: 'application/json'?   -  person Ashish Ranjan    schedule 13.12.2018
comment
вы пробовали error.error.toString()?   -  person Poul Kruijt    schedule 13.12.2018
comment
По responseType я рассматриваю заголовок contentType в ответ. Итак, когда ответ правильный и в ответ приходит двоичный файл, тип содержимого - это content-type: application / octet-stream, а там, где есть ошибка, и появляется только строка с ошибкой, это «content-type: text / plain». @xyz   -  person Nitish Kumar    schedule 13.12.2018
comment
error.error.toString () выводит [объект Blob] @PierreDuc   -  person Nitish Kumar    schedule 13.12.2018
comment
такое же поведение @SureshKumarAriya   -  person Nitish Kumar    schedule 13.12.2018


Ответы (5)


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

Сообщите 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.');
};

импортировать {catchError} из 'rxjs / operator';

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

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

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

person Gourishankar    schedule 13.12.2018
comment
Я не спрашиваю, как исправить ошибку! Я спрашиваю о варианте использования, в котором, указав responseType как blob. HttpErrorResponse неправильно анализируется Angular! - person Nitish Kumar; 13.12.2018

Попробуйте это

if(error.error instanceof Blob) {
    error.error.text().then(text => {
      let error_msg = (JSON.parse(text).message);
      console.log(error_msg)
    });
} else {
    //handle regular json error - useful if you are offline
}       
person dp_t    schedule 22.05.2020

Если возвращаемый 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
                }
            })    
    }

При желании вы можете иметь все внутри самого компонента.

person Ashish Ranjan    schedule 13.12.2018

Для будущих посетителей (поскольку название является общим):

Если бэкэнд возвращает JSON при ошибке (в идеале, следуя RFC 7807, что также будет означать application/problem+json content -type тоже), error.error является объектом JSON, а не строкой. Так, чтобы напечатать его, например, вам нужно сначала преобразовать его в строку:

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

Я считаю, что путаница начинается с официальной документации Angular, которая содержит следующее утверждение:

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

Но поскольку error.error является объектом JSON (в стандартных случаях), вы получаете [object Object] для тела вместо строкового представления этого объекта JSON. Тот же бесполезный результат, если вы попробуете ${error.error.toString()}.

person Voicu    schedule 04.12.2019
comment
Мне было интересно, строковый литерал - это действительная строка (строка) JSON. Есть способ сравнить это. var23 == JSON.stringify (var23) .toString () является ложным. var23.length - 5, а JSON.stringify (var23) .length - 7 из-за обозначения двойных кавычек JSON - person Vaisakh Rajagopal; 20.08.2020

Вы можете попробовать отдельную функцию обработчика ошибок, которая возвращает ответ как 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;
}
person Tushar Walzade    schedule 13.12.2018