web-dev-qa-db-ja.com

Angular 6)でHttpErrorResponseから本文を取得する方法

REST API呼び出しをファイルにダウンロードするAngularアプリで作成しました。

応答でファイルを期待しているので、responseTypeを 'blob'に設定しています。

ただし、サーバーで使用可能なファイルがない場合、レスポンスには404のエラーコードが含まれます。

しかし、HttpErrorResponseがerror.errorでblobオブジェクトを提供しているため、本文からそのエラーメッセージを解析できません。

Blobではなくエラーオブジェクトから実際の本文を取得するにはどうすればよいですか。

また、angularを構成する方法はありますか?API呼び出しが成功すると、要求をBLOBで解析します。

解決を望んでいる

4
Nitish Kumar

返されたContentTypeが異なる場合は、それを利用して、それが正しいバイナリファイルであるか、バイナリ形式のテキストであるかを区別できます。

リクエストを処理するサービスとビジネスロジックを実行するコンポーネントの2つのファイルがあるとします。

サービス内で、次のようなダウンロード方法を用意します。

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

必要に応じて、コンポーネント自体の中にすべてを含めることができます。

1
xyz

パラメータ:{観察: '応答'}、ヘッダーを含む完全な応答を読み取ることができます。以下の説明を参照してください。

監視オプションを使用して完全な応答が必要であることをHttpClientに通知します。

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

HttpClient.get()は、JSONデータだけでなく、型指定されたHttpResponseのObservableを返すようになりました。

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

'rxjs/operators'から{catchError}をインポートします。

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

参照: https://angular.io/guide/http :完全な応答を読み取る

それに応じてコードを変更します。

1
Gourishankar

次のように、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;
}
0
Tushar Walzade

今後の訪問者向け(タイトルが一般的なため):

エラー時にバックエンドが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 documentation から始まると思います。

_// 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オブジェクトである場合(標準の場合)、そのJSONオブジェクトの文字列表現ではなく、本文の_[object Object]_が出力されます。 ${error.error.toString()}を試しても同じ役に立たない出力です。

0
Voicu