2013-09-25 88 views
2

我有以下服务器代码使用Node.js和ajax进行长查询

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

和客户端代码:

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

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

确切的问题是,当前数据在数据库中发生变化时,响应没有得到发送。它时不时地工作,但它并不总是可靠的。

另一个问题是超时代码块不工作。如果请求的时间是30秒,那么应该发送一个空的响应以避免来自ajax的超时。

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

干杯。

回答

5

我已经想通了。该工作修正代码如下:

客户端:

<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.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); 

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

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

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

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

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

+1

嗨。一直给函数的递归调用会导致堆栈溢出? –

+0

我不认为会。我的服务器现在持续运行了一个多月,并没有造成任何溢出。也许node.js有一个机制来解决这个问题? – Sahil

+1

它不会导致堆栈溢出。这实际上并不是递归,因为'callNode'是由$ .ajax请求的'success'回调调用的,而不是'callNode'自己调用的。一旦'callNode'发出请求,它就会退出。 –