【问题标题】:How to get body from HttpErrorResponse in Angular 6?如何从 Angular 6 中的 HttpErrorResponse 获取正文?
【发布时间】:2019-05-14 11:00:36
【问题描述】:

我在我的 Angular 应用程序中创建了一个 REST API 调用,用于下载文件。

我将 responseType 设置为“blob”,因为我期待一个文件作为响应。

但是当服务器上没有可用的文件时,响应的错误代码为 404,即错误请求,正文中有一些消息。

但我无法解析来自正文的错误消息,因为 HttpErrorResponse 在 error.error 中提供了一个 blob 对象

如何从错误对象而不是 blob 中获取实际正文。

还有什么方法可以配置角度,在 api 调用成功时解析 blob 中的请求,否则在 json 中解析它???

期待解决

【问题讨论】:

  • 你试过 {responseType: 'blob' as 'json'}.?
  • 当您从 API 获取数据时,如果它是有效文件,那么 responseType 是什么,如果是错误,那么 responseType 是什么?它们是否不同,例如:对于有效文件:'application/octet-stream' 和对于错误:'application/json'
  • 你试过error.error.toString()吗?
  • 通过 responseType 我正在考虑 contentType 标头作为响应。因此,当响应正确且文件二进制响应时,内容类型为 content-type: application/octet-stream 并且出现错误且仅出现错误字符串时为“content-type: text/plain”。 @xyz
  • error.error.toString() 正在输出 [object Blob] @PierreDuc

标签: javascript angular angular-httpclient


【解决方案1】:

您可以尝试一个单独的错误处理函数,它以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;
}

【讨论】:

    【解决方案2】:

    参数:{ observe: 'response' },让你阅读完整的响应,包括标题。请参阅以下说明:-

    使用观察选项告诉 HttpClient 你想要完整的响应:

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

    现在 HttpClient.get() 返回一个类型化 HttpResponse 的 Observable 而不仅仅是 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.');
    };
    

    从 'rxjs/operators' 导入 { catchError};

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

    参考:https://angular.io/guide/http:阅读完整回复

    相应地更改您的代码。

    【讨论】:

    • 我不是在问如何处理错误!我在询问一个用例,其中通过将 responseType 提供为 blob。 Angular 没有正确解析 HttpErrorResponse !
    【解决方案3】:

    如果返回的 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
                    }
                })    
        }
    

    如果您愿意,您可以将所有内容都包含在组件本身中。

    【讨论】:

      【解决方案4】:

      对于未来的访问者(因为标题是通用的):

      如果后端在出错时返回 JSON(理想情况下,遵循 RFC 7807,这也意味着 application/problem+json 内容类型),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 对象(在标准情况下),您会打印出 [object Object] 的正文而不是该 JSON 对象的字符串表示形式。如果您尝试${error.error.toString()},则同样无益的输出。

      【讨论】:

      • 我想知道,作为字符串文字是一个有效的 JSON 字符串(“字符串”)。有没有办法比较一下。 "var23" == JSON.stringify("var23").toString() 是假的。 "var23".length 是 5 并且 JSON.stringify("var23").length 是 7,因为 JSON 双引号表示法
      【解决方案5】:

      试试这个

      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
      }       
      

      【讨论】:

        猜你喜欢
        • 2020-11-04
        • 2019-05-05
        • 2019-01-06
        • 2021-01-28
        • 1970-01-01
        • 2015-08-13
        • 2018-12-16
        • 2019-01-12
        相关资源
        最近更新 更多