Handling HTTP 401 with WWW-Authenticate in Cordova

2019-08-12 07:13发布

I'm currently working on a mobile app built on Cordova and Ionic. I am dealing with a third-party API (i.e. it cannot, and will not be changed for this app to work).

When a user of the app is unauthenticated - be that if their session has expired or otherwise - the API responds with an HTTP 401, with a WWW-Authenticate header.

In a browser while developing this is fine, but while on an iPhone, or in a simulator it does not appear, and the app has to reach the timeout period for the request. When that timeout is reached, the request is cancelled. This means that in the JavaScript, we simply get back a HTTP status of 0, with no real data to identify whether or not there was a timeout, or an authentication issue.

Currently, I've put in place some educated guesswork like checking if the phone has connectivity when a timeout occurs etc, but this is not an ideal solution as the user still has to wait for that timeout, and it's not always correct.

How can I check when the HTTP 401 dialog has appeared and is expecting a response? I need to be able to identify when an actual 401 occurs, and when a request simply times out.

If there is a method in JavaScript to accomplish then, then that'd be great. A native solution would also work, be it a plugin or otherwise.

3条回答
可以哭但决不认输i
2楼-- · 2019-08-12 07:19

Well I am not sure why the third-party API woudn't send you normal HTTP error codes. If you are connecting to the API with the use of $http you can add response interceptors to it, for example read next article:

http://codingsmackdown.tv/blog/2013/01/02/using-response-interceptors-to-show-and-hide-a-loading-widget/

Within the next error handler code you can add some code to evaluate the HTTP status code:

function error(response) {
    // Added code for specific HTTP error codes
    if (response.status === 401) {
        console.log('Received 401');
    }

    // get $http via $injector because of circular dependency problem
    $http = $http || $injector.get('$http');
    if($http.pendingRequests.length < 1) {
        $('#loadingWidget').hide();
    }
    return $q.reject(response);
}

Also see the AngularJS documentation about interceptors.

查看更多
劳资没心,怎么记你
3楼-- · 2019-08-12 07:29

A native solution would also work, be it a plugin or otherwise.

I had the same problem and I could fix it with the cordova http plugin. Just install it via ionic plugin add cordova-plugin-advanced-http (check documentation here). Then your xhttp calls will be done natively and not out of the webView. Then responses with a ´WWW-Authenticate´ headers will not timeout anymore and you can properly handle a 401

You can use it in your code like this:

try { // important since it will not work in dev mode in your browser (e.g. chrome)
    if (cordova && cordova.plugin && cordova.plugin.http) {

        var server_url = 'https://example.com';
        var your_endpoind = '/auth-me-example';

        cordova.plugin.http.useBasicAuth('some_user', 'and_password');
        cordova.plugin.http.setHeader(server_url, 'Content-type', 'application/json');

        cordova.plugin.http.get(server_url + your_endpoind, {}, {}, function (response) {
            console.log('response: ', JSON.stringify(response));
        }, function (response) {
            console.error('error response: ', JSON.stringify(response));
        });
    }
} catch (e) {
    console.error('could not make native HTTP request!');
}

PS: if you are using angular2+ npm install --save @ionic-native/http is also quite useful.

查看更多
太酷不给撩
4楼-- · 2019-08-12 07:30

I am dealing with the same issue at the moment.

The issue is that when a 401 is being returned, it has a WWW-Authenticate piece, which tells the browser to pop up that little popup for you to try again. This isn't handled "right" (depends on who you ask I guess) in the iOS web container, which results in Cordova never to see the request. The cordova bug is logged here: https://issues.apache.org/jira/browse/CB-2415

I don't understand how such a major issue hasn't been resolved, yet. But I am sure there are some technicalities around it. If you check out the updates, you see that Tobias Bocanegra ( https://github.com/tripodsan/cordova-ios/commit/5f0133c026d6e21c93ab1ca0e146e125dfbe8f7e ) added a "quick hack" to solve the problem. Maybe that helps you further. It didn't help me in my situation.

What I did in my case for a temporary fix: I passed the http requests into the loading modal, which has a cancel button. So, it is up to the user to cancel or just wait. It's horrible, but it worked in my case. (Internal app, etc.)

查看更多
登录 后发表回答