2013-09-25 84 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'發出請求,它就會退出。 –