Lansana Camara
Lansana Camara

Reputation: 9873

Angular2/Rxjs: 'catch' on observable giving ProgressEvent instead of json from response

In my HttpServive, I have shared http methods that will handle starting/ending the loading bar, setting the proper headers for JWT, and so on.

All is fine, but now I am trying to add some logic in the catch to check the response in the event of a non-200 status code (such as 401), so that I can do something and then re-make the failed request.

The problem is, the response I get back in the event of a non-200 status code is not accessible from that catch for whatever reason.

For instance, this is the code:

// ...

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

The console.log(error) outputs the error of type Response; The console.log(error.json()) outputs some data of type ProgressEvent.

Why am I getting a ProgressEvent, instead of the JSON sent from the non-200 status code response?

This is the 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
}

As you can see, the ProgressEvent is not my response. My response is a JSON object with just one error property, which contains a message and a status. This is just wrong, why don't I get my response?

Upvotes: 4

Views: 3954

Answers (1)

Ciro Corvino
Ciro Corvino

Reputation: 2128

I got a similar issue working on a spa project based on Angular and Asp.Net Core.

If it is the same issue it should have depend from the missing of CORS headers in the http response that client receives from server. This response violates the browser CORS policy and most likely depends from not handled run time errors in the server.

Even catching all errors and putting into returning response some info and http status, Angular, when occur CORS constraints violations, doesn't allow to have access to any info of the response, not even the http status, and so it produces the "empty" response:

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..

I solved this issue putting CORS headers into the response returned by the ASp.Net Core api server to the client in this way:

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

The code has to be put into in the Configure method of Startup class.

I hope that it could be of some help.

Upvotes: 1

Related Questions