如何从Angular 6中的HttpErrorResponse获取正文?

时间:2018-12-13 09:04:02

标签: javascript angular angular-httpclient

我已经在Angular应用程序中创建了一个REST API调用,可以下载文件。

我正在将responseType设置为“ blob”,因为我希望得到一个响应文件。

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

但是我无法从正文中解析该错误消息,因为HttpErrorResponse给了错误一个Blob对象。错误

如何从错误对象而不是blob获取实际主体。

还有任何方法可以配置角度,以便在api调用成功后将请求解析为blob,否则将其解析为json ???

希望获得解决方案

5 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:1)

尝试一下

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
}       

答案 2 :(得分:0)

  

您可以尝试使用单独的错误处理程序函数,该函数将响应返回为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;
}

答案 3 :(得分:0)

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

通过观察选项告诉HttpClient您想要完整的响应:

1.  Go to Data > Text to Columns  
2.  Choose Delimited > Next  
3.  Choose Semicolon > Next  
4.  Choose General or Text, whichever you prefer.  
5.  Click Finish.

现在HttpClient.get()返回一个类型为HttpResponse的Observable,而不仅仅是JSON数据。

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

并得到这样的Error主体:-

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

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

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

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

相应地更改代码。

答案 4 :(得分:0)

为将来的访问者(由于标题是通用的):

如果后端在发生错误时返回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()},则会产生无用的输出。