Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 2 REST request HTTP status code 401 changes to 0

Tags:

rest

cors

angular

I'm developing an Angular2 application. It seems when my access-token expires the 401 HTTP Status code gets changed to a value of 0 in the Response object. I'm receiving 401 Unauthorized yet the ERROR Response object has a status of 0. This is preventing me from trapping a 401 error and attempting to refresh the token. What's causing the 401 HTTP status code to be changed into HTTP status code of 0?

Here's screenshot from Firefox's console:

enter image description here

Here's my code:

get(url: string, options?: RequestOptionsArgs): Observable<any> 
{
    //console.log('GET REQUEST...', url);

    return super.get(url, options)
        .catch((err: Response): any =>
        {
            console.log('************* ERROR Response', err);

            if (err.status === 400 || err.status === 422)
            {
                return Observable.throw(err);
            }
            //NOT AUTHENTICATED
            else if (err.status === 401)
            {                   
                this.authConfig.DeleteToken();
                return Observable.throw(err);
            }               
            else
            {
                // this.errorService.notifyError(err);
                // return Observable.empty();
                return Observable.throw(err);
            }
        })
        // .retryWhen(error => error.delay(500))
        // .timeout(2000, new Error('delay exceeded'))
        .finally(() =>
        {
            //console.log('After the request...');
        });
}

This code resides in a custom http service that extends Angular2's HTTP so I can intercept errors in a single location.

In Google Chrome, I get this error message:

XMLHttpRequest cannot load https://api.cloudcms.com/repositories/XXXXXXXXXXXXXXXX/branches/XXXXXXXXXXXXXXXX/nodesXXXXXXXXXXXXXXXX. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://screwtopmedia.local.solutiaconsulting.com' is therefore not allowed access. The response had HTTP status code 401.

This is confusing because I am including 'Access-Control-Allow-Origin' header in request.

Here's a picture of results received in Google Chrome:

enter image description here

I've tried accessing 'WWW-Authenticate' Response Header as a means to trap for 401. However, the following code returns a NULL:

err.headers.get("WWW-Authenticate")

It's puzzling that I'm getting a CORS issue because I'm not getting any CORS errors when a valid access token is provided.

How do I trap for 401 HTTP status code? Why is 401 HTTP status code being changed to 0?

Thanks for your help.

like image 488
Tom Schreck Avatar asked Aug 17 '16 14:08

Tom Schreck


3 Answers

The issue is related to CORS requests, see this github issue

No 'Access-Control-Allow-Origin' header is present on the requested resource

means that 'Access-Control-Allow-Origin' is required in the response headers.

Angular is not getting any status codes, that's why it gives you a 0 which is caused by browser not allowing the xml parser to parse the response due to invalid headers.

You need to append correct CORS headers to your error response as well as success.

like image 63
Ankit Singh Avatar answered Nov 01 '22 16:11

Ankit Singh


If cloudcms.com do to not set the Access-Control-Allow-Origin in 401 response, then nothing much you can do. You properly have to open support ticket with them to confirm if that is normal behavior.

javascript in browsers(FF, Chrome & Safari) I tested won't receive any info if CORS error occur, other than status 0. Angular2 has no control of it.


I created a simple test and get the same result as yours:

geturl() {
    console.log('geturl() clicked');
    let headers = new Headers({ 'Content-Type': 'application/xhtml+xml' });
    let options = new RequestOptions({ 'headers': headers });
    this.http.get(this.url)
        .catch((error): any => {
            console.log('************* ERROR Response', error);
            let errMsg = (error.message) ? error.message :
                error.status ? `${error.status} - ${error.statusText}` : 'Web Server error';
            return Observable.throw(error);
        })
        .subscribe(
        (i: Response) => { console.log(i); },
        (e: any) => { console.log(e); }
        );
}

After much googling, I found the following(https://github.com/angular/angular.js/issues/3336):

lucassp commented on Aug 19, 2013

I found the issue for a while now but I forgot post here a reply. EVERY response, even Error 500, must have the CORS headers attached. If the server doesn't attach the CORS headers to the Error 500 response then the XHR Object won't parse it, thus the XHR Object won't have any response body, status, or any other response data inside.

Result from Firefox network monitor seems supporting the above reason.

Javascript request will receive empty response. javascript request

Plain url request(copy&paste the link in the address bar) will get response body Plain url request

Javascript use XHRHttpRequest for http communication.

When a XHR reply arrive, the browser will process the header, that's why you will see those 401 network messages. However, if the XHR reply is from a different host then the javascript AND the response header contain no CORS header(eg Access-Control-Allow-Origin: *), the browser will not pass any info back to the XHR layer. As a result, the reply body will be completely empty with no status(0).

I tested with FF 48.0.1, Chrome 52.0.2743.116 and Safari 9.1.2, and they all have the same behavior.

Use browser network monitor to check response header for those 401 Unauthorized entries, it is very likely that there is no Access-Control-Allow-Origin header and causing the issue you are facing. This can be a bug or by design on the service provider side.

Access-Control-Allow-Origin is a response only http header. For more information of https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#The_HTTP_response_headers

like image 25
John Siu Avatar answered Nov 01 '22 18:11

John Siu


I work for Cloud CMS. I can confirm that we properly set CORS headers on API calls. However, for 401 responses the headers are not getting set properly. This has been resolved and the fix will be available on the public API at the end of this week.

BTW if you use our javascript driver https://github.com/gitana/gitana-javascript-driver instead of writing to the API directly then the re-auth flow is handled automatically and you do not need to trap 401 errors at all.

like image 5
Harry Avatar answered Nov 01 '22 16:11

Harry