XHR没有获得正确的状态代码

时间:2016-12-27 00:33:47

标签: javascript ajax

这是一个服务器端函数,它接收POST请求并处理其响应。如您所见,当没有错误发生时,响应的状态代码为200。

app.post('/submit', function(req, res) {
    var p = new Promise(function(resolve, reject) {
        db.serialize(function() {
            db.run("INSERT INTO users VALUES (?, ?, ?, ?)",
            [req.query['email'], req.query['company'], req.query['subject'], req.query['text']],
            function (err) {
                if (err) {
                    console.error(err);
                    reject();
                } else {
                    console.log("Transaction passed");
                    resolve();
                }
            });
        });
    });
    p.then(function(){
        res.status(200).end();
    }).catch(function() {
        res.status(400).end();
    })
});

在客户端,我编写了一个JS函数,它向服务器发送一个AJAX POST请求并处理响应:

function addFormToDB(email, company, subject, text) { 
    var xhttp = new XMLHttpRequest();
    var params = "email=" + email + "&company=" + company + "&subject=" + subject + "&text=" + text;
    xhttp.open("POST", "http://127.0.0.1:3000/submit?" + params, true);
    xhttp.onreadystatechange = function() {
        console.log(xhttp.readyState + " " + xhttp.status);
        if (xhttp.readyState == 4 && xhttp.status == 200) {
            console.log("request " + params + " was sent to DB");
            alert("Thank You!");
        }
    };
    xhttp.send();
}

当我调用函数' addFormToDB'从浏览器的控制台窗口,它向服务器发送一个AJAX请求,并以xhhr.status 200返回。

然而,' addFormToDB'必须在用户填写表单并点击“提交”时调用。按钮。发生这种情况时,从服务器发送回浏览器的xhhr.status始终为0.我不知道原因。

以下是创建表单的HTML代码:

<form id="form">
        <label for="email"> E-mail: </label>
        <input id = "email"> <br>
        <label for="company"> Company: </label>
        <input id = "company"> <br>
        <label for="subject"> Subject: </label>
        <input id = "subject"> <br>
        <label for="text"> Text: </label>
        <input id = "text"> <br>
        <input type="submit" value="Submit" id="button"><br><br>
    </form>
...
<script>
$("#form").submit(function() {
    addFormToDB($("#email").val(), $("#company").val(), $("#subject").val(), $("#text").val())
});
</script>
你可以帮我找出这个bug吗?

1 个答案:

答案 0 :(得分:1)

当前的问题是,您不能阻止表单提交的默认操作 - 即将数据POST到服务器并重新加载页面。作为副作用,这将取消所有正在运行的Ajax请求,这会导致您看到的效果。

要阻止默认事件操作,请在事件对象上调用preventDefault()

parent_location

在当天,# This is a quick and open-ended script multi-threader searcher # #.Description # This script will allow any general, external script to be multithreaded by providing a single # argument to that script and opening it in a seperate thread. It works as a filter in the # pipeline, or as a standalone script. It will read the argument either from the pipeline # or from a filename provided. It will send the results of the child script down the pipeline, # so it is best to use a script that returns some sort of object. # # Authored by Ryan Witschger - http://www.Get-Blog.com # #.PARAMETER Command # This is where you provide the PowerShell Cmdlet / Script file that you want to multithread. # You can also choose a built in cmdlet. Keep in mind that your script. This script is read into # a scriptblock, so any unforeseen errors are likely caused by the conversion to a script block. # #.PARAMETER ObjectList # The objectlist represents the arguments that are provided to the child script. This is an open ended # argument and can take a single object from the pipeline, an array, a collection, or a file name. The # multithreading script does it's best to find out which you have provided and handle it as such. # If you would like to provide a file, then the file is read with one object on each line and will # be provided as is to the script you are running as a string. If this is not desired, then use an array. # #.PARAMETER InputParam # This allows you to specify the parameter for which your input objects are to be evaluated. As an example, # if you were to provide a computer name to the Get-Process cmdlet as just an argument, it would attempt to # find all processes where the name was the provided computername and fail. You need to specify that the # parameter that you are providing is the "ComputerName". # #.PARAMETER AddParam # This allows you to specify additional parameters to the running command. For instance, if you are trying # to find the status of the "BITS" service on all servers in your list, you will need to specify the "Name" # parameter. This command takes a hash pair formatted as follows: # # @{"ParameterName" = "Value"} # @{"ParameterName" = "Value" ; "ParameterTwo" = "Value2"} # #.PARAMETER AddSwitch # This allows you to add additional switches to the command you are running. For instance, you may want # to include "RequiredServices" to the "Get-Service" cmdlet. This parameter will take a single string, or # an aray of strings as follows: # # "RequiredServices" # @("RequiredServices", "DependentServices") # #.PARAMETER MaxThreads # This is the maximum number of threads to run at any given time. If resources are too congested try lowering # this number. The default value is 20. # #.PARAMETER SleepTimer # This is the time between cycles of the child process detection cycle. The default value is 200ms. If CPU # utilization is high then you can consider increasing this delay. If the child script takes a long time to # run, then you might increase this value to around 1000 (or 1 second in the detection cycle). # # #.EXAMPLE # Both of these will execute the script named ServerInfo.ps1 and provide each of the server names in AllServers.txt # while providing the results to the screen. The results will be the output of the child script. # # gc AllServers.txt | .\Run-CommandMultiThreaded.ps1 -Command .\ServerInfo.ps1 # .\Run-CommandMultiThreaded.ps1 -Command .\ServerInfo.ps1 -ObjectList (gc .\AllServers.txt) # #.EXAMPLE # The following demonstrates the use of the AddParam statement # # $ObjectList | .\Run-CommandMultiThreaded.ps1 -Command "Get-Service" -InputParam ComputerName -AddParam @{"Name" = "BITS"} # #.EXAMPLE # The following demonstrates the use of the AddSwitch statement # # $ObjectList | .\Run-CommandMultiThreaded.ps1 -Command "Get-Service" -AddSwitch @("RequiredServices", "DependentServices") # #.EXAMPLE # The following demonstrates the use of the script in the pipeline # # $ObjectList | .\Run-CommandMultiThreaded.ps1 -Command "Get-Service" -InputParam ComputerName -AddParam @{"Name" = "BITS"} | Select Status, MachineName # Param($Command = $(Read-Host "Enter the script file"), [Parameter(ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]$ObjectList, $InputParam = $Null, $MaxThreads = 20, $SleepTimer = 200, $MaxResultTime = 120, [HashTable]$AddParam = @{}, [Array]$AddSwitch = @() ) Begin{ $ISS = [system.management.automation.runspaces.initialsessionstate]::CreateDefault() $RunspacePool = [runspacefactory]::CreateRunspacePool(1, $MaxThreads, $ISS, $Host) $RunspacePool.Open() If ($(Get-Command | Select-Object Name) -match $Command){ $Code = $Null }Else{ $OFS = "`r`n" $Code = [ScriptBlock]::Create($(Get-Content $Command)) Remove-Variable OFS } $Jobs = @() } Process{ Write-Progress -Activity "Preloading threads" -Status "Starting Job $($jobs.count)" ForEach ($Object in $ObjectList){ If ($Code -eq $Null){ $PowershellThread = [powershell]::Create().AddCommand($Command) }Else{ $PowershellThread = [powershell]::Create().AddScript($Code) } If ($InputParam -ne $Null){ $PowershellThread.AddParameter($InputParam, $Object.ToString()) | out-null }Else{ $PowershellThread.AddArgument($Object.ToString()) | out-null } ForEach($Key in $AddParam.Keys){ $PowershellThread.AddParameter($Key, $AddParam.$key) | out-null } ForEach($Switch in $AddSwitch){ $Switch $PowershellThread.AddParameter($Switch) | out-null } $PowershellThread.RunspacePool = $RunspacePool $Handle = $PowershellThread.BeginInvoke() $Job = "" | Select-Object Handle, Thread, object $Job.Handle = $Handle $Job.Thread = $PowershellThread $Job.Object = $Object.ToString() $Jobs += $Job } } End{ $ResultTimer = Get-Date While (@($Jobs | Where-Object {$_.Handle -ne $Null}).count -gt 0) { $Remaining = "$($($Jobs | Where-Object {$_.Handle.IsCompleted -eq $False}).object)" If ($Remaining.Length -gt 60){ $Remaining = $Remaining.Substring(0,60) + "..." } Write-Progress ` -Activity "Waiting for Jobs - $($MaxThreads - $($RunspacePool.GetAvailableRunspaces())) of $MaxThreads threads running" ` -PercentComplete (($Jobs.count - $($($Jobs | Where-Object {$_.Handle.IsCompleted -eq $False}).count)) / $Jobs.Count * 100) ` -Status "$(@($($Jobs | Where-Object {$_.Handle.IsCompleted -eq $False})).count) remaining - $remaining" ForEach ($Job in $($Jobs | Where-Object {$_.Handle.IsCompleted -eq $True})){ $Job.Thread.EndInvoke($Job.Handle) $Job.Thread.Dispose() $Job.Thread = $Null $Job.Handle = $Null $ResultTimer = Get-Date } If (($(Get-Date) - $ResultTimer).totalseconds -gt $MaxResultTime){ Write-Error "Child script appears to be frozen, try increasing MaxResultTime" Exit } Start-Sleep -Milliseconds $SleepTimer } $RunspacePool.Close() | Out-Null $RunspacePool.Dispose() | Out-Null } 具有同样的效果,但现在。function submitHandler(e) { e.preventDefault(); // some processing, for example Ajax // the browser will not issue a traditional POST request } 是可行的方法。

对您的代码的进一步评论:

客户端

不要推出自己的Ajax功能。 Ajax库非常方便,经过充分测试,并提供易于阅读的Ajax支持,可以防止常见错误并透明地完成各种繁重的工作。只需使用其中一个many libraries即可。

使用jQuery,你似乎正在使用它,该函数变得像这样直截了当:

return false;

服务器端

不要做自己的宣传。它可能看起来很容易,但就像Ajax一样,有足够的东西可能出错并容易被忽视。让一个库为你做,或者使用一个为你做的包装库。对于node-sqlite3,存在一个这样的包装器库:co-sqlite3。我建议你看一下。

您的代码可能如下所示:

preventDefault()

或者使用库样本中显示的async / yield变体之一。