回调中的XHR响应数据错误

时间:2017-03-10 14:25:09

标签: javascript json callback

我目前正在尝试编写一个简单的应用程序,它通过多个异步xhr请求从服务器请求数据。响应在每个请求的onreadystatechanged回调中处理。

目前,如果我异步执行超过10个请求,我开始从请求回调中获取错误的数据,又名:

book 1: abc --> correct
book 2: efg --> correct
book 3: efg --> wrong
book 4: kjl --> correct

我回到了onreadystatehandler,甚至在这里请求对象包含错误的数据(req.responseText)。 网址(req.responseURL)是正确的,因为请求的每个网址都会被回调一次,只是输入了错误的数据。

所以我在浏览器devtools看了一下我收到的回复,以确认服务器确实提供了正确的数据,情况就是这样。

老实说,我没有任何关于如何解决这个问题的想法,因为服务器正在使用正确的数据进行响应,但请求回调只是"使用"错误的,即使有正确的网址。

这就是我尝试实现它的方式:

var sendRequest = function(url, callback){
    var req = new XMLHttpRequest();
    req.overrideMimeType('text/plain');
    req.open("GET", url, true);
    if(callback) {
        req.onreadystatechange = (function(req,callback){
            return function() {
                if(req.readyState == 4) {
                    if(req.status == 200 || req.status == 304) {

                        var response;
                        try {
                            response = JSON.parse(req.responseText);
                        } catch(error) {
                            callback(undefined, req.responseText);
                            return;
                        }

                        if(response.error)
                            callback(response.error, response);
                        else
                            callback(undefined, response);

                    }else{
                        callback("Error", req.responseText)
                    }
                }
            };
        })(req,callback);
    }
    req.send(params);
}

以下是我用于发送请求的代码示例。

var booksToLoad = 0;
for(var i = 0; i < libraries.length; i++) {
  (function(i) {
    sendRequest('/LibraryList?'+'Id='+libraries[i]._id, function(err, response) {
        libraries[i] = response.library;    
        booksToload += libraries[i].books.length;
        for(var j=0; j < libraries[i].books.length; j++) {
            (function (i, j) {                          
                sendRequest('/BookList?'+'Id='+libraries[i].books[j]._id, function (err, response) {
                    libraries[i].books[j].pages = response.pages;
                    --booksToLoad;
                    if(booksToLoad == 0)
                        return;
                });
            })(i, j);
        }
    });
  })(i);
}

我尝试过的事情:

  1. 将for循环转换为递归调用 - &gt;有效,但速度慢。
  2. 将请求存储在数组中并迭代以发送 - >&gt;
  3. 检查JSON.parse()是否以某种方式破坏了它 - &gt; nope普通数据也错了
  4. 强制不使用标头缓存 - &gt;
  5. 尝试了不同的浏览器(chrome + firefox) - &gt;
  6. 如前所述,我很困惑的事实是来自服务器的数据很好并且使用正确的req.responseURL调用回调但是错误的数据(不是从响应中的url中获取)。

    感谢您的帮助,我在这里不知所措......

    Maggistro

    编辑:我有点放弃,并决定是不好的设计,无论如何发送这个数量的xhr请求。所以我将这些请求捆绑在一起(整个库,包含书籍+页面)。

    这样,如果软件包稍后变大,我就不得不管理我所请求的数据(我有完全控制权),而不是浏览器允许的请求数量。

    不知道这是不是一个好主意,但我不能在这个问题上花更多的时间。 仍然想确切知道导致此行为的原因以供将来参考。

    感谢您的时间,

    Maggistro

1 个答案:

答案 0 :(得分:1)

试试这个:

function fetchLibrary(i){
    sendRequest('/LibraryList?Id='+libraries[i]._id, function(err, response) {
        libraries[i] = response.library;    
        for(var j=0; j < libraries[i].books.length; j++)
            fetchBooks(i,j);
    });
}

function fetchBooks(i,j){                         
    sendRequest('/BookList?Id='+libraries[i].books[j]._id, function (err, response) {
        libraries[i].books[j].pages = response.pages;
    });
}

for(var i = 0; i < libraries.length; i++) {
    fetchLibrary(i);
}

并且,使用网络选项卡确保正在发送的请求确实返回正确的结果。如果他们不这样做(检查响应),请修复服务器端获取组件。

==========

好的,这里是服务器端和客户端组件的完全测试和功能示例。使用它作为参考:

服务器端(service.php):

<?php


$libraries = [
    ["id" => 1, "name" => "foo"],
    ["id" => 2, "name" => "bar"],
    ["id" => 3, "name" => "baz"]
];

$books = [
    ["library_id" => 1, "id" => 1, "pages" => 10],
    ["library_id" => 1, "id" => 2, "pages" => 11],
    ["library_id" => 1, "id" => 3, "pages" => 12],
    ["library_id" => 2, "id" => 4, "pages" => 13],
    ["library_id" => 2, "id" => 4, "pages" => 14],
    ["library_id" => 2, "id" => 5, "pages" => 15],
    ["library_id" => 3, "id" => 6, "pages" => 16],
    ["library_id" => 3, "id" => 7, "pages" => 17],
    ["library_id" => 3, "id" => 8, "pages" => 18]
];
header("Content-type: application/json;encoding=utf-8");
if (!isset($_REQUEST["request_id"])){
    $protocol = (isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0');
    header($protocol . ' 500 Error - Specify Request ID');
    exit;
}
$request_id  = $_REQUEST["request_id"];
$library_id = isset($_REQUEST["library_id"])?$_REQUEST["library_id"]:null;

$ret = [];
if ($library_id){
    // fetch list of books for the library_id
    foreach ($books as $book){
        if ($book["library_id"] == $library_id){
            $ret[] = $book;
        }
    }
} else {
    // fetch list of libraries
    $ret = $libraries;
}
print_r(json_encode(["request_id" => $request_id, "result" => $ret], JSON_PRETTY_PRINT));

客户方:

<script>
function r(url, callback){
    var req = new XMLHttpRequest();
    req.responseType = "json";
    url += url.match(/\?/)?"&":"?";
    var request_id = new Date().getTime();
    url += "request_id=" + request_id; 
    req.open("GET", url, true);
    req.onreadystatechange = function(){
        if (req.readyState == 4) {
            status = req.status;
            if (status == 200) {
                console.log("URL " + url + " received", req.response);
                callback(req.response, request_id);
            } else {
                window.alert("Problem with request " + url);
                console.error(url + " failed. Status: " + status);
                console.log(req.response);
            }
        }
    }
    req.send();
}

function fetchLibraries(){
    r("service.php", function(data, id){
        for (var x in data.result){
            fetchBooks(data.result[x]);
        }
    });
}

function fetchBooks(library){
    var e = document.createElement("p");
    document.body.appendChild(e);
    e.innerHTML = "loading " + library.id;
    r("service.php?library_id=" + library.id, function(data){
        e.innerHTML = "";
        for (var x in data.result){
            var book = data.result[x];
            e.innerHTML += "Book: " + book.id + ", pages: " + book.pages + "<br>";
        }
    });
}

fetchLibraries();
</script>

经过全面测试,效果非常好。