1480 votes

Comment gérer une demande de redirection après un appel Ajax de jQuery ?

J'utilise $.post() pour appeler une servlet à l'aide d'Ajax, puis en utilisant le fragment HTML résultant pour remplacer un fichier de type div dans la page actuelle de l'utilisateur. Toutefois, si la session expire, le serveur envoie une directive de redirection pour renvoyer l'utilisateur vers la page de connexion. Dans ce cas, jQuery remplace l'élément div avec le contenu de la page de connexion, obligeant les yeux de l'utilisateur à assister à une scène rare.

Comment gérer une directive de redirection à partir d'un appel Ajax avec jQuery 1.2.6 ?

1 votes

(pas une réponse en tant que telle) - J'ai fait cela dans le passé en modifiant la bibliothèque jquery et en ajoutant une vérification de la page de connexion à chaque XHR complet. Ce n'est pas la meilleure solution car il faudrait le faire à chaque mise à jour, mais cela résout le problème.

1 votes

Voir la question connexe : stackoverflow.com/questions/5941933/

0 votes

En HttpContext.Response.AddHeader et vérifier le succès d'ajaxsetup est la voie à suivre.

741voto

Steg Points 4835

J'ai lu cette question et j'ai mis en œuvre l'approche qui a été indiquée concernant la définition de la réponse Code d'état HTTP à 278 afin d'éviter que le navigateur ne gère les redirections de manière transparente. Même si cela a fonctionné, j'étais un peu mécontent car c'est un peu un hack.

Après avoir creusé un peu plus, j'ai abandonné cette approche et j'ai utilisé JSON . Dans ce cas, toutes les réponses aux requêtes AJAX ont l'attribut code de statut 200 et le corps de la réponse contient un objet JSON qui est construit sur le serveur. Le JavaScript du client peut alors utiliser l'objet JSON pour décider de ce qu'il doit faire.

J'ai eu un problème similaire au vôtre. J'exécute une requête AJAX qui a 2 réponses possibles : une qui redirige vers le navigateur à une nouvelle page et une qui remplace un formulaire HTML existant sur la page actuelle avec un nouveau formulaire. Le code jQuery pour faire cela ressemble à quelque chose comme :

$.ajax({
    type: "POST",
    url: reqUrl,
    data: reqBody,
    dataType: "json",
    success: function(data, textStatus) {
        if (data.redirect) {
            // data.redirect contains the string URL to redirect to
            window.location.href = data.redirect;
        } else {
            // data.form contains the HTML for the replacement form
            $("#myform").replaceWith(data.form);
        }
    }
});

L'objet JSON "data" est construit sur le serveur pour avoir 2 membres : data.redirect y data.form . J'ai trouvé cette approche bien meilleure.

63 votes

Comme indiqué dans la solution dans stackoverflow.com/questions/503093/ il est préférable d'utiliser window.location.replace(data.redirect) ; que window.location.href = data.redirect ;

8 votes

Y a-t-il une raison pour laquelle il ne serait pas préférable d'utiliser les codes HTTP sur l'action ? Par exemple un code 307 qui est une redirection temporaire HTTP ?

18 votes

@Sergei Golos la raison est que si vous faites une redirection HTTP, la redirection n'arrive jamais au callback ajax success. Le navigateur traite la redirection en délivrant un code 200 avec le contenu de la destination de la redirection.

265voto

J'ai résolu ce problème en :

  1. Ajout d'un en-tête personnalisé à la réponse :

    public ActionResult Index(){
        if (!HttpContext.User.Identity.IsAuthenticated)
        {
            HttpContext.Response.AddHeader("REQUIRES_AUTH","1");
        }
        return View();
    }
  2. Lier une fonction JavaScript au ajaxSuccess et vérifie si l'en-tête existe :

    $(document).ajaxSuccess(function(event, request, settings) {
        if (request.getResponseHeader('REQUIRES_AUTH') === '1') {
           window.location = '/';
        }
    });

123voto

Thomas Hansen Points 3348

Aucun navigateur ne gère correctement les réponses 301 et 302. En fait, la norme stipule même qu'ils doivent les traiter "de manière transparente", ce qui est un énorme casse-tête pour les fournisseurs de bibliothèques Ajax. Sur Ra-Ajax nous avons été contraints d'utiliser le code de statut de réponse HTTP 278 (juste un code de succès "inutilisé") pour gérer les redirections transparentes du serveur...

Cela m'ennuie vraiment, et si quelqu'un ici a un peu d'influence sur le W3C, j'apprécierais que vous fassiez savoir au W3C que vous êtes en train d'utiliser le système de gestion de l'information. connaître que nous devons vraiment gérer les codes 301 et 302 nous-mêmes... ;)

3 votes

Pour ma part, je propose que 278 fasse partie de la spécification HTTP officielle.

2 votes

Ne les traite-t-il pas déjà de manière transparente ? Si une ressource a été déplacée, la traiter de manière transparente signifie répéter la requête sur l'URL fournie. C'est ce à quoi je m'attendrais en utilisant l'API XMLHttpRequest.

0 votes

@PhilippeRathé D'accord. Une manipulation transparente, c'est exactement ce que je veux. Et je ne sais pas pourquoi elle est considérée comme mauvaise.

103voto

Elliot Vargas Points 3917

La solution finalement mise en œuvre a consisté à utiliser un wrapper pour la fonction de rappel de l'appel Ajax et à vérifier dans ce wrapper l'existence d'un élément spécifique dans le fragment HTML renvoyé. Si l'élément est trouvé, le wrapper exécute une redirection. Sinon, le wrapper transmet l'appel à la fonction de rappel réelle.

Par exemple, notre fonction wrapper était quelque chose comme :

function cbWrapper(data, funct){
    if($("#myForm", data).length > 0)
        top.location.href="login.htm";//redirection
    else
        funct(data);
}

Ensuite, lors de l'appel Ajax nous avons utilisé quelque chose comme :

$.post("myAjaxHandler", 
       {
        param1: foo,
        param2: bar
       },
       function(data){
           cbWrapper(data, myActualCB);
       }, 
       "html"
);

Cela a fonctionné pour nous car tous les appels Ajax ont toujours renvoyé du HTML à l'intérieur d'un élément DIV que nous utilisons pour remplacer un morceau de la page. De plus, nous avions seulement besoin de rediriger vers la page de connexion.

4 votes

Notez que ceci peut être raccourci en function cbWrapper(funct) { return function(data) { if($("#myForm", data).size() > 0) top.location.href="login" ; else funct(data) ; } } } . Vous n'avez alors besoin de cbWrapper(myActualCB) que lorsque vous appelez .post. Oui, le code dans les commentaires est un désordre mais il faut le noter :)

0 votes

La taille est dépréciée, vous pouvez donc utiliser .length à la place de size.

74voto

BrianY Points 211

J'aime la méthode de Timmerz avec un léger zeste de citron. Si jamais tu es renvoyé contentType de texte/html quand vous attendez JSON vous êtes probablement redirigé. Dans mon cas, je recharge simplement la page, et elle est redirigée vers la page de connexion. Oh, et vérifiez que le statut de jqXHR est 200, ce qui semble idiot, car vous êtes dans la fonction d'erreur, non ? Sinon, les cas d'erreur légitimes forceront un rechargement itératif (oops).

$.ajax(
   error:  function (jqXHR, timeout, message) {
    var contentType = jqXHR.getResponseHeader("Content-Type");
    if (jqXHR.status === 200 && contentType.toLowerCase().indexOf("text/html") >= 0) {
        // assume that our login has expired - reload our current page
        window.location.reload();
    }

});

1 votes

Merci beaucoup Brian, votre réponse était la meilleure pour mon scénario, bien que j'aimerais qu'il y ait une vérification plus sûre, comme la comparaison de l'url/page vers laquelle la redirection est faite, au lieu de la simple vérification du "content-type". Je n'ai pas réussi à trouver la page vers laquelle la redirection est effectuée à partir de l'objet jqXHR.

0 votes

J'ai vérifié l'état 401 et ensuite la redirection. Ça marche comme sur des roulettes.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X