0
votes

Problème Obtenir la bonne valeur de retour lors de la validation d'un utilisateur utilisant AJAX

Je voudrais obtenir la valeur appropriée pour oklogin code> lorsque l'utilisateur est incorrect et arrêtez le formulaire d'aller de l'avant, mais j'ai remarqué que lorsque j'appelle la fonction est exécutée en premier lieu. que l'appel AJAX, qui devrait être en arrière.

Je veux que la fonction Ajax met à jour ma variable OkLogin sur FALSE, une inadéquation accessible. P>

<form action="test.html" onsubmit="return loginProcess();">
    <label for="usernameLogin" class="col-sm-4 col-form-label">Username</label>
    <input class="form-control" type="text" id="usernameLogin" required>
    <label for="passwordLogin" class="col-sm-4 col-form-label">Password</label>
    <input class="form-control" type="password" id="passwordLogin" required>
    <input type="submit" class="btn btn-primary btn-block" id="loginSubmitBtn" value="Login">
</form>

<script>

function loginProcess() {
    let users, usernameLogin, passwordLogin;
    let ajaxCall = new XMLHttpRequest();
    let okLogin = true;

    usernameLogin = document.getElementById("usernameLogin").value;
    passwordLogin = document.getElementById("passwordLogin").value;

    ajaxCall.onreadystatechange = function() {

        if (ajaxCall.readyState == 4 && ajaxCall.status == 200) {

            users = JSON.parse(ajaxCall.responseText);

            for (let item in users) {

                if (item === "username") {
                    if (usernameLogin !== users["username"]) {
                        okLogin = false;
                    }
                    console.log("Username: " + okLogin);
                }

                if (item === "password") {
                    if (passwordLogin !== users["password"]) {
                        okLogin = false;
                    }
                }
            }
        }
    }
    ajaxCall.open("GET", "docs/users.json", true);
    ajaxCall.send();
    return okLogin;
}

</script>


3 commentaires

Le problème est que vous appelez le xmlhttprequest asynchrone, qui doit être effectué dans votre cas de manière synchrone à la place parce que votre Onsubmit aura besoin de quelque chose à retourner ( vrai ou faux) à ce moment-là dans le temps. Essayez de changer cette ligne ajaxcall.open ("get", "docs / users.json", true); to ajaxcall.open ("get", "docs / users.json", faux); et voir ce qui se passe.


@GetSet Cela ne devrait jamais être recommandé car c'est une mauvaise pratique. JavaScript est parfaitement capable de gérer le code ASYNC avec des rappels, des promesses et ASYNC / AWAIT.


@Emielzuurbier, j'ai plus posté mon commentaire car il utilise de près la base de code de l'OP de près, et donc un apprentissage pourrait avoir lieu dans cette approche, tout en clarifiant où l'erreur est. Personnellement, j'irais un itinéraire différent en caché le bouton de soumettre réel à partir d'affichage, puis avec un bouton d'envoi intermédiaire (de type = "bouton" ) qui gère tout ordre avant de soumettre le formulaire directement ou via le bouton caché.


3 Réponses :


0
votes

Cela ne fonctionnera pas car les demandes AJAX sont asynchrones. En d'autres termes, le code dans onreadyStatechange code> n'est défini que pour être exécuté plus tard, une fois que l'appel AJAX est revenu. C'est pourquoi votre méthode est renvoyée avant la fin de l'appel AJAX.

Je remarquerais également que l'authentification est une chose importante à avoir raison, et je pense que vous feriez bien de regarder quelques exemples d'une authentification correcte. De l'apparence de celui-ci, vous retournez une liste de tous les noms d'utilisateur et mots de passe en clairexuant dans l'appel. C'est un design très insécurisé. Si vous avez des intentions d'utilisation de cela pour autre chose qu'une expérience, vous ne devriez pas faire les choses de cette façon. En fait, même si vous n'utilisez que cela comme une expérience, je suggérerais d'essayer de faire une manière différente pour obtenir l'expérience de faire des choses comment elles devraient être faites. P>

En tout cas, la manière de rendre ce travail tel quel serait, au lieu de revenir, prenez des mesures dans le rappel. Ce n'est pas clair dans le code que vous avez soumis exactement ce qui se produira lorsque la méthode code> loginprocess code> (de l'apparence ne se passe rien. Vous pouvez peut-être appeler une autre méthode avec votre fonction OnReadyStatechange CODE> avec une fonction vraie ou false, et laissez cette fonction gérer ce qui devrait se produire en fonction d'une connexion réussie ou infructueuse. P>

Exemple: P>

ajaxCall.onreadystatechange = function() {
  if (ajaxCall.readyState == 4 && ajaxCall.status == 200) {
    [your code to check the login here]
    someOtherFunction(okLogin)
  }
}


1 commentaires

Merci beaucoup pour la recommandation. J'ai fait des exemples de départ ce mois-ci, mais je ne comprends pas comment cela fonctionne, j'ai fait beaucoup d'exemples, mais cela semble étrange et compliqué, est-ce une meilleure façon de faire cela? Je ne suis pas un programmeur professionnel, je n'ai donc pas d'expérience dans la sécurité des connexions et des moyens modernes de récupérer des données.



0
votes

Bienvenue à. Votre problème est dû à la nature du JavaScript asynchrone. Votre XMLHTTPQUEST prend un certain temps pour obtenir une réponse. À cause de cela, vous devez attendre avant de retourner une valeur jusqu'à ce que la demande soit terminée. Vous retournerez maintenant instantanément oklogin code> sans la demande de la modifier.

Donc, vous devez retarder cela. Vous pouvez utiliser async code> / attendre code> pour attendre la demande de finition et continuez avec votre processus. Tout est basé sur promet , un objet qui peut chaîner des rappels avec le alors code> méthode. p>

au lieu du XMLHTTPQUEST code> constructeur, essayez le Fetch API code> . C'est une version plus moderne du même principe, mais avec un flux de travail plus simple et plus puissant et cela fonctionne avec des promesses. P>

Maintenant avec async / attendre, vous pouvez rendre votre fonction asynchrone, ce qui signifie que cela prendra du temps à complète, mais faire autre chose quand c'est fait. Le mot clé code> attendre code> peut être mis à l'avant de toute fonction de retour de la promesse, comme Fetch, de attendre em> la fonction pour terminer et obtenir la valeur de celle-ci. P>

Dans votre code, cela ressemblerait à ceci. P>

loginProcess().then((loginStatus) => {
  console.log(loginStatus)
});


3 commentaires

Vous avez dit que je peux essayer d'utiliser Fetch ou Async / Attendre, mais lequel des deux devrais-je utiliser? Ont-ils une différence? Parce que vous avez utilisé Async / attendre ici, même si vous avez dit que Fetch était le meilleur à utiliser. Je voudrais donc en savoir plus à ce sujet et merci beaucoup! Et avons-je écrit le deuxième code? Celui avec le "alors" et la console?


Utilise les deux. Fetch est un substitut de XMLHTTPRequest et retournera une promesse quand elle est appelée. Avec async / attendre, vous pouvez attendre la récupération de résoudre (finition) et stocker la valeur qu'elle revient. Sans async / attendre, vous devriez compter sur la méthode , qui est une sorte de la même chose mais fonctionne différemment. La deuxième partie avec le puis et console doit être dans votre gestionnaire de soumission.


Ah Okey, qu'entendez-vous par "Soumettre le gestionnaire"?



1
votes

Comme écrit, votre code reviendra toujours vrai; La valeur de oklogin , que vous définissez pour être vraie, ne sera jamais autre chose que cela. C'est parce que ajaxcall.send () est asynchrone: il commence l'appel Ajax, mais c'est tout; Cela n'attend pas que l'appel réussisse (ou échoue). Donc, la prochaine chose qui se passe, chaque fois que vous appelez ajaxcall.send () , est-ce que vous retournez la valeur actuelle de oklogin , qui sera vrai à chaque fois, car Tout code qui pourrait changer sa valeur n'aura pas encore été exécuté. (Il ne sera exécuté qu'après une réponse à votre demande Ajax.) J'espère que cela a du sens; Ceci est une erreur courante lors de la gestion des méthodes telles que envoyer () qui sont asynchrones - que commencent quelque chose (dans ce cas une demande AJAX) mais N'attendez pas qu'il finit avant de revenir. (Et dans votre cas, retournez une valeur qui sera vraie à chaque fois, car chaque fois, le code de votre ajaxcall.onreadytstatechange sera exécuté après vous retournerez Oklogin .)

Une solution serait de rendre l'appel AJAX synchrone, en passant false au lieu de true comme dernier argument sur Ouvrir () . Cela fonctionnera, mais c'est une idée grave. Faire des sourcils synchrones sont profondément fronça les sourcils, car il provoque la suspension du navigateur de l'utilisateur jusqu'à ce qu'une réponse soit reçue. Cela pourrait prendre quelques millisecondes (pas un problème) mais si la réponse est lente en arrivant, elle pourrait prendre une seconde (très mauvaise) ou plusieurs secondes (totalement inacceptable).

Je suggérerais ceci approche: changez ceci ... xxx

... à ceci: xxx

En d'autres termes, lorsque l'utilisateur Soume le formulaire, appelez loginprocess () , qui commence votre appel AJAX, puis renvoyez FALSE (qui, pour l'instant, gardez le formulaire d'être soumis). Nous allons maintenant ignorer la valeur de retour de loginprocess () ; Ce n'est pas pertinent. J'ai également ajouté une classe à votre formulaire, que nous allons utiliser dans une minute.

Maintenant, notre stratégie sera de faire votre rappel (votre ajaxcall .EnreadyStatechange Code), qui sera exécuté après une réponse réussie, soumettez votre formulaire uniquement si oklogin est vrai. Pour ce faire, changez votre code comme suit: xxx

Vous pouvez également utiliser des promesses ( alors () , etc.) mais c'est probablement un bon Idée de comprendre les rappels avant de vous attaquer à des promesses, si vous essayez de comprendre les concepts asynchrones.

Note finale: Vous pouvez également utiliser async / attendre mais avant de le faire, mais avant de le faire, D Voulez comprendre des promesses (et avant ces rappels) - mais plus important, async / attendre ne peut pas être disponible dans tous vos navigateurs cible; Pas, mais non, mais pas les versions de bord précédentes.

espère que cela aide!


4 commentaires

Merci beaucoup pour cela!! Donc, la fonction reviendra toujours fausse, la seule façon de soumettre quelque chose qui le fait manuellement de l'intérieur de la fonction avec la fonction Soumettre. Parce que cela fonctionne de manière asynchrone, il n'arrive donc pas que la fonction se poursuive, d'accord que j'ai eu. J'ai quelques questions cependant: - À propos de la sécurité ici, que dois-je faire pour que ce soit sécurisé? Ceci n'est qu'un test mini-backend avec JSON, je ne sais pas où commencer. - À propos de "Fetch" et "Async / Attendre", sont-ils les mêmes? Lequel devrais-je utiliser? Lequel est le meilleur pour ce genre de travail?


@JFelya Ceci - développeur.mozilla.org/en-us/docs/ Web / API / FETCH_API traite des différences entre FETCH et XMLHTTPRequest (vous utilisez ce dernier, bien sûr). Fetch est plus récent et plus puissant mais ne fonctionne pas sur certains navigateurs plus âgés. En ce qui concerne ASYNC / AWAIT: Ce n'est pas une alternative à l'une quelconque - c'est une fonction de langue nouvelle qui peut rendre le code asynchrone plus facile à travailler avec (comme des promesses peut). Je suggère d'apprendre d'abord des rappels, puis des promesses, puis asynchrones / attendre (étroitement liées aux promesses). En outre, fonctions génératrices. Mais je m'attaquerais d'abord aux rappels.


@JFelya comme pour la sécurité: vous devez toujours utiliser Post au lieu d'obtenir lors de l'envoi d'informations sensibles. La poste est la valeur par défaut pour XMLHTTPQUEST, mais obtenir est la valeur par défaut pour la soumission d'un formulaire. Donc, vous devriez ajouter méthode = "post" à votre tag; Nom d'utilisateur / mot de passe ne sera pas visible dans votre URL de demande (beaucoup plus en sécurité). Bien sûr, vous ne devez également envoyer que des informations sensibles sur HTTPS, et non http. Si votre site n'est pas https en ce moment, ce qui en fait un problème de configuration serveur; Votre code resterait probablement le même.


Merci pour cela. J'ai essayé de lire le lien avant pendant un certain temps, mais c'était tellement frustrant que je ne pouvais pas comprendre une chose de cet article, je n'avais rien, désolé, peut-être que c'est ma faute.