Javascript 使用AJAX验证用户时,获取正确的返回值时出现问题

Javascript 使用AJAX验证用户时,获取正确的返回值时出现问题,javascript,html,ajax,Javascript,Html,Ajax,当用户不正确时,我想为okLogin获取正确的值,并阻止表单向前运行,但我注意到,当我调用函数时,返回比ajax调用先执行,ajax调用应该向后执行 我希望ajax函数在出现不匹配时将okLogin变量更新为false <form action="test.html" onsubmit="return loginProcess();"> <label for="usernameLogin" class="col-sm-4 col-form-label">Usern

当用户不正确时,我想为
okLogin
获取正确的值,并阻止表单向前运行,但我注意到,当我调用函数时,返回比ajax调用先执行,ajax调用应该向后执行

我希望ajax函数在出现不匹配时将okLogin变量更新为false

<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>

用户名
密码
函数loginProcess(){
让用户、用户名登录、密码登录;
设ajaxCall=new XMLHttpRequest();
让okLogin=true;
usernameLogin=document.getElementById(“usernameLogin”).value;
passwordLogin=document.getElementById(“passwordLogin”).value;
ajaxCall.onreadystatechange=函数(){
if(ajaxCall.readyState==4&&ajaxCall.status==200){
users=JSON.parse(ajaxCall.responseText);
for(让项目进入用户){
如果(项目==“用户名”){
if(usernameLogin!==users[“username”]){
okLogin=false;
}
console.log(“用户名:”+okLogin);
}
如果(项目==“密码”){
if(passwordLogin!==用户[“密码”]){
okLogin=false;
}
}
}
}
}
打开(“GET”,“docs/users.json”,true);
ajaxCall.send();
返回okLogin;
}

这将不起作用,因为ajax请求是异步的。换句话说,
onreadystatechange
中的代码只有在ajax调用返回后才被定义为稍后执行。这就是为什么您的方法在ajax调用完成之前返回

我还要指出,身份验证是正确进行的一件重要事情,我认为您最好看看一些正确身份验证的示例。从外观上看,您正在以明文形式返回呼叫中所有用户名和密码的列表。这是一个非常不安全的设计。如果你打算把它用于实验以外的任何事情,你不应该这样做。事实上,即使你只是把它作为一个实验,我建议你尝试用不同的方式去做,只是为了获得经验去做应该做的事情

无论如何,让它按原样工作的方法是,在回调中采取一些操作,而不是返回。在您提交的代码中,当
loginProcess
方法返回时,不清楚会发生什么(从外观上看,什么也没有发生)。也许,您可以使用
onreadystatechange
函数调用其他方法,并使用true或false,让该函数处理基于成功或不成功登录应该发生的任何事情

例如:

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

另外,我建议您研究一种更现代的处理ajax请求的方法,

欢迎使用。您的问题是由于异步JavaScript的性质造成的。XMLHTTPRequest需要一些时间才能得到响应。因此,在返回值之前需要等待,直到请求完成。现在,您立即返回
okLogin
,而请求没有机会更改它

所以你需要推迟。您可以使用
async
/
wait
等待请求完成并继续处理。这一切都基于一个对象,该对象可以使用
then
方法将回调链接在一起

不要使用
XMLHTTPRequest
构造函数,而是尝试使用。这是同一原则的更现代版本,但有一个更简单、更强大的工作流程,并且它与承诺一起工作

现在使用async/await,您可以使函数异步,这意味着它需要一些时间才能完成,但在完成后要做一些其他事情。
await
关键字可以放在任何承诺返回函数(如fetch)前面,以等待函数完成并从中获取值

在您的代码中,它看起来是这样的

async function loginProcess() {
    let usernameLogin, passwordLogin, response, users;
    let okLogin = true;

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

    response = await fetch("docs/users.json");
    users = await response.json();

    for (let item in users) {
      if (item === "username" && usernameLogin !== item) {
        okLogin = false;
      } else if (item === "password" && passwordLogin !== item) {
        okLogin = false;
      }
    }

    return okLogin;
}
该函数使用
fetch
获取数据,等待数据完成,然后将JSON的结果转换为可用值,并从那里继续。 由于
loginProcess
本身是异步的,因此它会返回一个承诺。仔细阅读你如何使用它们。它们是JavaScript的一个非常强大的功能


还要注意@bodicious。关于代码中的安全问题,他提出了一些非常好的观点。执行验证服务器端,其中代码对用户不可见。

编写时,代码将始终返回true;您定义为true的
okLogin
的值将是除此之外的任何值。这是因为
ajaxCall.send()
是异步的:它启动了AJAX调用,但仅此而已;它不会等待调用成功(或失败)。因此,接下来发生的事情是,每次调用
ajaxCall.send()
,都返回当前值
okLogin
,每次都是真的,因为任何可能更改其值的代码都不会被执行。(只有在您的AJAX请求得到响应后才会执行)希望这是有意义的;在处理像
send()
这样的异步方法时,这是一个常见的错误,这些方法启动某些东西(在本例中是AJAX请求),但不等待它完成后再返回。(在您的情况下,每次返回的值都是true,因为每次返回
okLogin
后,
ajaxCall.onreadystatechange
函数中的代码都会执行)

一种解决方案是通过将
false
而不是
true
作为
open()
的最后一个参数,使AJAX调用同步。这会奏效,但这是一个严重的坏主意;做同步AJAX是非常困难的
loginProcess().then((loginStatus) => {
  console.log(loginStatus)
});
<form action="test.html" onsubmit="return loginProcess();">
<form class="main-form" action="test.html" onsubmit="loginProcess(); return false;">
    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;
                    }
                }
            }
            // ***** Add the following three lines:
            if (okLogin) {
                document.querySelector('form.main-form').submit()
            }
        }
    }