Angular 5 管理带有 blob 响应和 json 错误的 http get
Posted
技术标签:
【中文标题】Angular 5 管理带有 blob 响应和 json 错误的 http get【英文标题】:Angular 5 manage http get with blob response and json errors 【发布时间】:2018-09-03 22:03:19 【问题描述】:我正在开发一个 Angular 5 应用程序。我必须从我的后端应用程序下载一个文件,为此我只需调用如下函数:
public executeDownload(id: string): Observable<Blob>
return this.http.get(this.replaceUrl('app/download', denunciaId), responseType: 'blob').map(result =>
return result;
);
然后调用我刚刚调用的下载服务:
public onDownload()
this.downloadService.executeDownload(this.id).subscribe(res =>
saveAs(res, 'file.pdf');
, (error) =>
console.log('TODO', error);
// error.error is a Blob but i need to manage it as RemoteError[]
);
当后端应用程序处于特定状态时,它不会返回 Blob,而是返回一个 HttpErrorResponse
,其中在其 error
字段中包含一个 RemoteError 数组。 RemoteError 是我编写的用于管理远程错误的接口。
在 catch 函数中,error.error 是一个 Blob。如何将 Blob 属性转换为 RemoteError[]
数组?
提前致谢。
【问题讨论】:
【参考方案1】:使用FileReader
的建议对我来说还不够,因为它们不适用于HttpTestingController
(因为blob 到json 的转换是异步的)。在我的案例中,业力测试总是在该承诺得到解决之前完成。这意味着我不能编写使用这种方法来测试不愉快路径的业力测试。我将建议一个将 blob 同步转换为 json 的解决方案。
服务类:
public doGetCall(): void
this.httpClient.get('/my-endpoint', observe: 'body', responseType: 'blob').subscribe(
() => console.log('200 OK'),
(error: HttpErrorResponse) =>
const errorJson = JSON.parse(this.blobToString(error.error));
...
);
private blobToString(blob): string
const url = URL.createObjectURL(blob);
xmlRequest = new XMLHttpRequest();
xmlRequest.open('GET', url, false);
xmlRequest.send();
URL.revokeObjectURL(url);
return xmlRequest.responseText;
角度测试:
it('test error case', () =>
const response = new Blob([JSON.stringify(error-msg: 'get call failed')]);
myService.doGetCall();
const req = httpTestingController.expectOne('/my-endpoint');
expect(req.request.method).toBe('GET');
req.flush(response, status: 500, statusText: '');
... // expect statements here
);
错误子句中已解析的errorJson
现在将包含error-msg: 'get call failed'
。
【讨论】:
【参考方案2】:可能像大多数人一样,我希望我的错误消息同步。我通过将它放在一个警告框中来处理这个问题:
(err:any) =>
// Because result, including err.error, is a blob,
// we must use FileReader to display it asynchronously:
var reader = new FileReader();
reader.onloadend = function(e)
alert("Error:\n" + (<any>e.target).result);
reader.readAsText(err.error);
let errorMessage = "Error: " + err.status.toString() + " Error will display in alert box.";
// your code here to display error messages.
,
【讨论】:
【参考方案3】:响应应该是一个 Blob,但显然情况并非如此。 为避免此错误,请将 responseType 从 blob 更改为 arraybuffer。
public executeDownload(id: string): Observable<Blob>
return this.http.get(this.replaceUrl('app/download', denunciaId), responseType: 'arraybuffer').map(result =>
return result;
);
【讨论】:
【参考方案4】:这是一个已知的Angular issue,在该线程中,JaapMosselman 提供了一个非常好的解决方案,涉及创建一个 HttpInterceptor
,它将 Blob 转换回 JSON。
使用这种方法,您不必在整个应用程序中进行转换,当问题得到解决后,您只需将其删除即可。
import Injectable from '@angular/core';
import HttpInterceptor, HttpHandler, HttpRequest, HttpEvent, HttpErrorResponse from '@angular/common/http';
import Observable, throwError from 'rxjs';
import catchError from 'rxjs/operators';
@Injectable()
export class BlobErrorHttpInterceptor implements HttpInterceptor
public intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>>
return next.handle(req).pipe(
catchError(err =>
if (err instanceof HttpErrorResponse && err.error instanceof Blob && err.error.type === "application/json")
// https://github.com/angular/angular/issues/19888
// When request of type Blob, the error is also in Blob instead of object of the json data
return new Promise<any>((resolve, reject) =>
let reader = new FileReader();
reader.onload = (e: Event) =>
try
const errmsg = JSON.parse((<any>e.target).result);
reject(new HttpErrorResponse(
error: errmsg,
headers: err.headers,
status: err.status,
statusText: err.statusText,
url: err.url
));
catch (e)
reject(err);
;
reader.onerror = (e) =>
reject(err);
;
reader.readAsText(err.error);
);
return throwError(err);
)
);
在你的 AppModule 或 CoreModule 中声明它:
import HTTP_INTERCEPTORS from '@angular/common/http';
...
@NgModule(
...
providers: [
provide: HTTP_INTERCEPTORS,
useClass: BlobErrorHttpInterceptor,
multi: true
,
],
...
export class CoreModule
【讨论】:
应该是公认的答案,完美,复制/粘贴。【参考方案5】:如文档“从 Blob 读取内容的唯一方法是使用 FileReader。” https://developer.mozilla.org/en-US/docs/Web/API/Blob.
编辑: 如果你需要blob的一部分,你可以做一个切片,它返回新的blob, 然后使用文件阅读器。
【讨论】:
以上是关于Angular 5 管理带有 blob 响应和 json 错误的 http get的主要内容,如果未能解决你的问题,请参考以下文章
Angular 6获取带有httpclient问题的响应标头
如何在 Angular 5 中解析和播放数据库中的 Blob/二进制数据
带有 Angular2 应用程序和 NodeJs 的 Docker 容器没有响应
如何在 Angular 中从服务器获取带有 jwt 令牌的响应标头