Gérer la réponse HTTP 302 de proxy dans angularjs

j'ai un mandataire inversé qui vérifie l'authentification globale pour plusieurs applications. Lorsque l'utilisateur est déconnecté mais qu'il essaie toujours d'utiliser mon application, le mandataire envoie une réponse 302:

HTTP/1.1 302 Found
Date: Wed, 11 Sep 2013 09:05:34 GMT
Cache-Control: no-store
Location: https://other.url.com/globalLoginPage.html
Content-Length: 561
Content-Type: text/html; charset=iso-8859-1
Via: 1.1 my-proxy.com
Connection: Keep-Alive

dans angularJs, le rappel d'erreur est appelé mais les en-têtes de réponse sont vides, l'état est 0 et les données sont une chaîne vide. Il semble donc que je ne peux vraiment rien faire pour gérer la réponse...

J'ai vu plusieurs questions sur la sujet, et je ne comprends toujours pas ce qui se passe (CORS en raison du proxy ou autre domaine dans l'emplacement?, 302 comportement du navigateur?).

En particulier, il y a cette partie d'une réponse ( https://stackoverflow.com/a/17903447/1093925 ):

Note: Si votre serveur définit un code de réponse de 301 ou 302, vous ne pourrez pas obtenir l'en-tête Location, car il sera suivi automatiquement et de manière transparente par l'objet XMLHttpRequest.

Qu'en est-il de cet objet XMLHttpRequest?

Dans une très ancienne version de Chrome (Je ne peux pas utiliser une version plus récente), je peux voir qu'une requête correspondante dans le panneau réseau, mais elle semble échouer car il n'y a pas de réponse.

Dans la dernière version de firefox, il ne se passe rien.

puis-je faire quelque chose à ce sujet, puisque je ne peux pas changer la configuration du proxy et réponse?

mise à jour:

J'ai rejoué mon scénario aujourd'hui, et grâce à une nouvelle version de firebug, j'ai pu obtenir plus de détails sur ce qui se passe.

Je n'étais pas loin de l'anwser dans ma question : la politique inter-domaines.

Puisqu'il s'agit d'une requête HTTP faite par mon application, le navigateur refuse la requête XMLHttpRequest suivante (qui In-app ressemble à la même requête). Conséquent l'erreur et la réponse vide.

Donc je pense qu'il n'y a rien de spécial que je puisse faire à ce sujet

29
demandé sur Community 2013-09-11 13:38:41

3 réponses

j'ai eu le même problème dans mon application. Vous ne pouvez pas vraiment "attraper" une réponse de redirection 302. Le navigateur l'attrape avant Angular get il est main dessus. donc en fait, lorsque vous recevez votre réponse - il est déjà trop tard.

la mauvaise nouvelle : ce n'est pas un problème dans la plateforme angulaire. Le xmlHttpRequest ne supporte pas ce type de comportement, et le navigateur agit avant que vous puissiez faire quoi que ce soit à ce sujet. référence: prévenir redirection de Xmlhttprequest

la bonne nouvelle : il y a plusieurs façons de contourner ce problème, en interceptant la réponse - et de trouver un moyen de reconnaître que c'est votre adorable 302. C'est un piratage, mais c'est le mieux que tu puisses faire pour le moment.

So. Par exemple, dans mon application, la redirection était de retour à la connexion.la page html de l'application, et dans l'application j'ai eu la réponse avec un statut 200 et les données de la réponse a été le contenu de mon login.la page html. donc dans mon intercepteur, j'ai vérifié si le résultat est une chaîne (généralement pas! donc - pas de l'efficacité de prob..) et si oui, - vérifier si c'est ma connexion.la page html. comme ça, je pourrais attraper la redirection et la gérer à ma façon.

yourApp.factory('redirectInterceptor', ['$location', '$q', function($location, $q) {
    return function(promise) {
        promise.then(
            function(response) {
                if (typeof response.data === 'string') {
                    if (response.data.indexOf instanceof Function &&
                        response.data.indexOf('<html id="ng-app" ng-app="loginApp">') != -1) {
                        $location.path("/logout");
                        window.location = url + "logout"; // just in case
                    }
                }
                return response;
            },
            function(response) {
                return $q.reject(response);
            }
        );
        return promise;
    };
}]);

alors insérez cet intercepteur dans votre application. quelque chose comme ceci:

$httpProvider.responseInterceptors.push('redirectInterceptor');

bonne chance.

38
répondu Ofer Segev 2017-05-23 11:54:48

votre redirection 302 est gérée directement par le navigateur et il n'y a rien que vous puissiez faire directement. Vous pouvez, cependant, utiliser un httpInterceptor pour vous aider. Vous aurez besoin d'inclure $httpProvider dans votre liste d'applications, et puis quelque part dans votre fonction de configuration mettre une référence à elle comme ceci:

$httpProvider.responseInterceptors.push('HttpInterceptor');

un intercepteur d'échantillon ressemble à ceci:

window.angular.module('HttpInterceptor', [])
.factory('HttpInterceptor', ['$q', '$injector',
    function($q, $injector) {
        'use strict';

        return function(promise) {
            return promise.then(success, error);
        };

        function success(response) {
            return response;
        }

        function error(response) {
            var isAuthRequest = (response.config.url.indexOf('/v1/rest/auth') !== -1);

            //if we are on the authenticating don't open the redirect dialog
            if (isAuthRequest) {
                return $q.reject(response);
            }

            //open dialog and return rejected promise
            openErrorDialog(response);
            return $q.reject(response);
        }

        function openErrorDialog(response) {
            $injector.get('$dialog').dialog({
                backdropFade: true,
                dialogFade: true,
                dialogClass: 'modal newCustomerModal',
                resolve: {
                    errorData: function() {
                        return response.data;
                    },
                    errorStatus: function() {
                        return response.status;
                    }
                }
            })
            .open('/views/error-dialog-partial.htm',
                'errorDialogController')
            .then(function(response) {
                if (response) {
                    window.location = '/';
                }
            });
        }
    }
]);
3
répondu MBielski 2016-01-14 20:56:17

j'ai eu un problème très similaire, et j'ai considéré la solution fournie par Ofer Segev, mais Vérifier le contenu de la réponse pour voir si elle correspondait à un fragment html d'une autre page m'a semblé trop hacky. Que se passe-t-il quand quelqu'un change cette page?

heureusement, j'avais aussi le contrôle du backend, donc au lieu de retourner un 302 (redirection), j'ai retourné un 403 (Interdit), et j'ai passé l'endroit désiré dans les en-têtes. Contrairement à la 302, la 403 sera traités dans votre gestionnaire d'erreur, où vous pouvez décider quoi faire ensuite. Voici mon handler résultant:

function ($scope, $http) {
    $http.get(_localAPIURL).then(function (response) {
            // do what I'd normally do
        }, function (response) {
        if (response.status == 403)
        {
            window.location.href = response.headers().location;
        }
        else
        {
            // handle the error
        }
1
répondu plunkg 2016-09-20 17:28:56