Angular2 / Rxjs:' catch' on observable从响应中提供ProgressEvent而不是json

时间:2017-04-30 11:25:50

标签: angular typescript rxjs

在我的HttpServive中,我共享了http方法,用于处理开始/结束加载栏,为JWT设置正确的标题,等等。

一切都很好,但现在我试图在catch中添加一些逻辑来检查非200状态代码(例如401)的响应,以便我可以做一些事情然后重新制作失败的请求。

问题是,无论出于何种原因,无法从catch访问非200状态代码时返回的响应。

例如,这是代码:

// ...

return this.http[method](url, options || defaultOptions)
    .map((res: Response) => res.json()) // <--- gives JSON from response
    .catch((error: any)) => {
        console.log(error);
        console.log(error.json()); // <--- should give JSON from response, but gives ProgressEvent instead
        return Observable.throw(error.json()); // also gives ProgressEvent when I 'subscribe' to the observable
    })
    .finally(() => {
        this.loadingBarService.complete();
    });

console.log(error)输出Response类型的错误; console.log(error.json())输出ProgressEvent类型的一些数据。

为什么我会获得ProgressEvent,而不是从非200状态代码响应发送的JSON?

这是ProgressEvent

{
    bubbles: false,
    cancelBubbles: false,
    cancelable: false,
    composed: false,
    currentTarget: XMLHttpRequest,
    defaultPrevented: false,
    eventPhase: 0,
    isTrusted: true,
    lengthComputable: false,
    loaded: 0,
    path: Array(0),
    returnValue: true,
    srcElement: XMLHttpRequest,
    target: XMLHttpRequest,
    timeStamp: 1234.115,
    total: 0,
    type: "error",
    __proto__: ProgressEvent
}

如您所见,ProgressEvent不是我的回答。我的响应是一个JSON对象,只有一个error属性,其中包含一条消息和一个状态。这是错的,为什么我没有得到我的答复?

1 个答案:

答案 0 :(得分:1)

在基于Angular和Asp.Net Core的水疗项目中,我遇到了类似的问题。

如果是同一问题,则应该取决于客户端从服务器接收到的http响应中缺少CORS标头。 此响应违反了浏览器的CORS策略,很可能取决于服务器中未处理的运行时错误。

即使捕获所有错误并在返回的响应中放入一些信息和http状态,Angular在发生CORS约束违例时也不允许访问响应的任何信息,甚至http状态也无法访问,因此它会产生“空”响应:

Response {_body: ProgressEvent, status: 0, ok: false, statusText: "", headers: Headers, …} headers : Headers {_headers: Map(0), _normalizedNames: Map(0)} ok : false status : 0 statusText : "" type : 3 url : null..

我解决了这个问题,通过以下方式将CORS标头放入ASp.Net Core API服务器返回给客户端的响应中:

   app.UseExceptionHandler(appError => {
                appError.Run(async context => {

                    var _config = ServiceProviderFactory.ServiceProvider.GetService<AppConfigurations>();

                    context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
                    context.Response.ContentType = "application/json";
                    context.Response.Headers.Add("Access-Control-Allow-Origin", $"{_config.AngularSiteUrl}");
                    context.Response.Headers.Add("Access-Control-Allow-Headers", "access-control-allow-origin,authorization,content-type");

                    var contextFeature = context.Features.Get<IExceptionHandlerFeature>();
                    if (contextFeature != null) {

                        var ex = contextFeature.Error;

                        var sp = services.BuildServiceProvider();
                        var _logger = sp.GetService<IGenericRepository<Log>>();

                        _logger.AddAndSave(new Log {
                            Description = "Exception not handled occurred",
                            Reason = ex.ToString(),
                            Type = "Error"
                        });

                         await context.Response.WriteAsync(
                            JsonConvert.SerializeObject(new {
                            Status = context.Response.StatusCode,
                            Message = "Internal Server Error."
                        }));
                    }
                });

必须将代码放入Configure类的Startup方法中。

我希望这会有所帮助。