javascript 使用 Node.js 和 ajax 进行长轮询

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19010263/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 14:03:13  来源:igfitidea点击:

Long polling with Node.js and ajax

javascriptmysqlajaxnode.js

提问by Sahil

I have following server code.

我有以下服务器代码

var http = require('http');
var mysql = require('mysql');
var querystring = require('request');
var util = require('util');
var url = require('url');

var singer_name;
var currentmodif, lastmodif;
var requests=[];
var response;

var connection = mysql.createConnection({
  host     : 'localhost',
  user     : 'someone',
  password : 'xxxxxxx',
  database : 'rest',  //mysql database to work with (optional)
});
connection.connect(); //connect to mysql

connection.query('SELECT * FROM musics WHERE id=1', function(err, rows, fields) {
  if (err) throw err;

  singer_name=rows[0].singer_name;
  currentmodif=rows[0].time_added;
});


http.createServer(function (req, res) {
    console.log('request received');

    requests.push({
        response: res,
        timestamp: new Date().getTime()
    });

    if(req.method=='GET'){
        var url_parts = url.parse(req.url,true);
        lastmodif = url_parts.query.timestamp;
    }

    //check_update(req, res);

}).listen(9000);


setInterval(function() {

    var expiration = new Date().getTime() - 30000;

    for (var i = requests.length - 1; i >= 0; i--) {
        //console.log("Request timestamp: "+requests[i].timestamp+" Expiration : "+expiration);
        response = requests[i].response;
        if (requests[i].timestamp < expiration) {
            console.log("The condition is met");
            response.writeHead(200, {
            'Content-Type'   : 'text/plain',
            'Access-Control-Allow-Origin' : '*'
            });

            // return response
            response.write('_testcb(\'ok\')', 'utf8');
            response.end();
            //break;
        }
    }

    connection.query('SELECT * FROM musics WHERE id=1', function(err, rows, fields) {
        if (err) throw err;
        currentmodif=rows[0].time_added;        
            //console.log("currentmodif: "+currentmodif+" lastmodif: "+lastmodif);
        if (currentmodif > lastmodif){
            singer_name=rows[0].singer_name; 
            var _arrays = {'singer_name': singer_name, 'time': currentmodif}
            var data = "_testcb"+"("+JSON.stringify(_arrays)+")";
            response.writeHead(200, {
            'Content-Type'   : 'text/plain',
            'Access-Control-Allow-Origin' : '*'
            });
            if (response.end(data))
            console.log("Response successfully sent");
            //return false;
        }

    });
}, 2000);

and Client code:

和客户端代码:

<html>
<head>
    <script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
    <title>Node.js Ajax test</title>
</head>
<body>

</body>
<script>
var timestamp = "1380020402";
function callNode() {

var time = "1380020402";
    $.ajax({
        url: 'http://xx.xxx.xx.xxx:9000/',
        dataType: "jsonp",
        data: {"timestamp":timestamp},
        type: 'POST',
        jsonpCallback: "_testcb",
        cache: false,
        timeout: 35000,
        success: function(response, code, xhr) {
            if ('ok' == response) {
                callNode();
                return false;
            }

            console.log(response);

            timestamp = response.time;
            // make new call
            callNode();
        },
        error: function(jqXHR, textStatus, errorThrown) {
            console.log('error ' + textStatus + " " + errorThrown);
        }
    });
}
$(function () {
    callNode();
});
</script>
</html>

I am trying to do a long polling. So until a data in database is updated, the response to ajax request should be paused but the above code is not working. I am making the ajax request from different domain and therefore using jsonp.

我正在尝试进行长轮询。因此,在更新数据库中的数据之前,应暂停对 ajax 请求的响应,但上述代码不起作用。我正在从不同的域发出 ajax 请求,因此使用 jsonp。

Exact problem is that currently when the data is changed in database the response doesn't get sent. It works every now and then but it is not consistently reliable.

确切的问题是,当前在数据库中更改数据时,不会发送响应。它时不时地工作,但它并不总是可靠的。

Another problem is that the code block for time out is not working. If the request is 30 seconds old then a blank response should be sent in order to avoid the timeout from ajax.

另一个问题是超时的代码块不起作用。如果请求是 30 秒,则应发送空白响应以避免 ajax 超时。

If someone can help then I would appreciate.

如果有人可以提供帮助,我将不胜感激。

Cheers.

干杯。

回答by Sahil

I have figured this out. Amended code that work is as below:

我已经想通了。修改后的代码如下:

Client side:

客户端:

<html>
<head>
    <script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
    <title>Node.js Ajax test</title>
</head>
<body>

</body>
<script>
var timestamp;
function callNode() {

    $.ajax({
        url: 'http://xx.xxx.xx.xxx:9000/',
        dataType: "jsonp",
        data: {"timestamp":timestamp},
        //type: 'POST', //don't need this with jsonp
        jsonpCallback: "_testcb",
        cache: false,
        timeout: 35000,
        success: function(response, code, xhr) {
            if ('ok' == response) {
                console.log(response);
                callNode();
                return false;
            }

            console.log(response);

            timestamp = response.time;
            // make new call
            callNode();
        },
        error: function(jqXHR, textStatus, errorThrown) {
            console.log('error ' + textStatus + " " + errorThrown);
        }
    });
}
$(function () {
    setTimeout(callNode, 1); //call function with setTimeout in order to avoid ugly constant browser loading 
});
</script>
</html>

Server Side (server.js):

服务器端(server.js):

var http = require('http');
var mysql = require('mysql');
var util = require('util');
var url = require('url');

var singer_name, currentmodif, lastmodif, request, response, time_of_request;

//var requests=[];

var connection = mysql.createConnection({
  host     : 'localhost',
  user     : 'someone',
  password : 'xxxxxx',
  database : 'rest',  //mysql database to work with (optional)
});
connection.connect(); //connect to mysql

connection.query('SELECT * FROM musics WHERE id=1', function(err, rows, fields) {
  if (err) throw err;

  singer_name=rows[0].singer_name;
  currentmodif=rows[0].time_added;
});


http.createServer(function (req, res) {
    request = req;
    response = res;
    time_of_request = new Date().getTime();
    console.log('request received');


    if(req.method=='GET'){
        var url_parts = url.parse(req.url,true);
        lastmodif = url_parts.query.timestamp;
    }

    req.on('error', function(e) {
        console.log('problem with request: ' + e.message);
    });

    //checkupdate();     

}).listen(9000);

var response;

function checkupdate() { 

    var expiration = new Date().getTime() - 30000;

    //for (var i = requests.length - 1; i >= 0; i--) {
        //console.log("Request timestamp: "+time_of_request+" Expiration : "+expiration);
        if (time_of_request < expiration) {
            console.log("The condition is met");
            // return response
            response.write('_testcb(\'ok\')', 'utf8');
            response.end();
        }
    //}

    connection.query('SELECT * FROM musics WHERE id=1', function(err, rows, fields) {
        if (err) throw err;
        currentmodif=rows[0].time_added;

        if (lastmodif == undefined)
            lastmodif = 0;

        console.log("currentmodif: "+currentmodif+" lastmodif: "+lastmodif);

        if (currentmodif > lastmodif){
            singer_name=rows[0].singer_name;  
            var _arrays = {'singer_name': singer_name, 'time': currentmodif} 
            var data = "_testcb"+"("+JSON.stringify(_arrays)+")";

            //response.writeHead(200, { 'content-type':'application/json',
                                    //'Access-Control-Allow-Origin' : '*'});
            //response.write(data); 
            response.end(data);
            console.log("Response successfully sent");
            //return false;
        }

    });
};

setInterval(checkupdate, 2000);

The problem was with the server side. The response object was not available (it was undefined) when server wanted to reply and therefore the response was not being sent. I may have overlooked the error in the node.js's console.

问题出在服务器端。当服务器想要回复时,响应对象不可用(未定义),因此未发送响应。我可能忽略了 node.js 控制台中的错误。

This is almost a complete example of long polling with node.js with MYSQL database. This script will wait for fresh data to become available before replying to the ajax request. If fresh data (in MYSQL) is not available within 30 seconds of the request then a fake reply is made so that the request does not time out. There is a condition in ajax's success callback that re-initiates this ajax request when this demo response is received, therefore making this an infinite loop.

这几乎是使用 node.js 和 MYSQL 数据库进行长轮询的完整示例。此脚本将在回复 ajax 请求之前等待新数据可用。如果新数据(在 MYSQL 中)在请求的 30 秒内不可用,则进行虚假回复,以便请求不会超时。ajax 的成功回调中有一个条件,它会在收到此演示响应时重新启动此 ajax 请求,因此使其成为无限循环。

I have successfully tested code above and it seems to work fine. I ran the script and then updated the data in my database (mainly the time_added field) and this triggered a reply to my waiting ajax call with new data from node.js's server.

我已经成功测试了上面的代码,它似乎工作正常。我运行了脚本,然后更新了我的数据库中的数据(主要是 time_ added 字段),这触发了对我等待的 ajax 调用的回复,其中包含来自 node.js 服务器的新数据。

I hope this code helps someone out there.

我希望这段代码可以帮助那里的人。

Checkout tutorial here for further explanation: http://www.sahilsaid.com/blog/long-polling-node-js-mysql-database-ajax/

在这里结帐教程进一步解释:http: //www.sahilsaid.com/blog/long-polling-node-js-mysql-database-ajax/