Angular 5中如何处理带Blob响应与JSON错误的HTTP GET请求
处理Angular 5下载请求中的JSON格式错误
这个问题我之前做Angular文件下载时也碰到过——当你把responseType设为blob后,不管后端返回的是正常文件还是JSON格式的错误响应,Angular都会把响应体包装成Blob,没法直接解析成JSON来获取错误信息。下面给你几种实用的解决方式:
1. 在请求调用处直接处理错误
最简单的方式是在subscribe的错误回调里,把错误的Blob转换成文本再解析成JSON:
public onDownload() { this.downloadService.executeDownload(this.id).subscribe( res => { saveAs(res, 'file.pdf'); }, (error: HttpErrorResponse) => { // 后端返回的错误体是Blob类型,需要先读取成文本 if (error.error instanceof Blob) { const reader = new FileReader(); // 读取完成后解析JSON reader.onload = () => { try { const errorDetails = JSON.parse(reader.result as string); console.error('下载失败:', errorDetails); // 这里可以给用户展示具体错误,比如弹窗提示 alert(`下载出错:${errorDetails.message || '未知错误'}`); } catch (e) { // 如果解析失败,说明不是JSON格式的错误(比如二进制文件损坏) alert('下载文件时发生未知错误'); } }; reader.readAsText(error.error); } else { // 非Blob类型的错误,直接处理 console.error('下载失败:', error.error); alert(`下载出错:${error.error?.message || error.message}`); } } ); }
2. 在服务层封装错误处理逻辑
如果多个地方都有下载需求,可以把错误处理逻辑封装到服务里,让调用更简洁:
首先修改服务中的executeDownload方法:
import { catchError } from 'rxjs/operators'; import { Observable, throwError } from 'rxjs'; import { HttpErrorResponse } from '@angular/common/http'; public executeDownload(id: string): Observable<Blob> { return this.http.get(this.replaceUrl('app/download', id), {responseType: 'blob'}).pipe( catchError((error: HttpErrorResponse) => { return new Observable<never>(observer => { if (error.error instanceof Blob) { const reader = new FileReader(); reader.onload = () => { try { const errorObj = JSON.parse(reader.result as string); observer.error(errorObj); } catch (e) { observer.error('无法解析错误信息,请稍后重试'); } }; reader.onerror = () => observer.error('读取错误信息失败'); reader.readAsText(error.error); } else { observer.error(error.error || error.message); } }); }) ); }
然后调用的时候就可以直接处理解析好的错误:
public onDownload() { this.downloadService.executeDownload(this.id).subscribe( res => saveAs(res, 'file.pdf'), error => { console.error('下载失败:', error); alert(`下载出错:${error.message || '未知错误'}`); } ); }
3. 全局拦截器统一处理(推荐)
如果你的应用中有很多下载请求,用全局HTTP拦截器来统一处理这种Blob错误会更高效,不用每个请求都写重复代码:
首先创建一个拦截器:
import { Injectable } from '@angular/core'; import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpErrorResponse } from '@angular/common/http'; import { Observable, throwError } from 'rxjs'; import { catchError } from 'rxjs/operators'; @Injectable() export class DownloadErrorInterceptor implements HttpInterceptor { intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { // 只处理responseType为blob的请求 if (req.responseType === 'blob') { return next.handle(req).pipe( catchError((error: HttpErrorResponse) => { return new Observable<never>(observer => { if (error.error instanceof Blob) { const reader = new FileReader(); reader.onload = () => { try { const errorJson = JSON.parse(reader.result as string); observer.error(errorJson); } catch (e) { observer.error('下载文件时发生错误'); } }; reader.readAsText(error.error); } else { observer.error(error.error || error.message); } }); }) ); } // 非Blob请求直接放行 return next.handle(req); } }
然后在AppModule中注册这个拦截器:
import { HTTP_INTERCEPTORS } from '@angular/common/http'; import { DownloadErrorInterceptor } from './download-error.interceptor'; @NgModule({ providers: [ { provide: HTTP_INTERCEPTORS, useClass: DownloadErrorInterceptor, multi: true // 允许多个拦截器 } ] }) export class AppModule { }
这样所有设置了responseType: 'blob'的请求,遇到JSON错误时都会自动解析成JSON对象抛出,调用处只需要正常处理错误即可。
内容的提问来源于stack exchange,提问作者xcesco
相关产品推荐
相关产品推荐

