套接字挂断:Websocket向Twitter API发出GET HTTPS请求

时间:2016-03-30 03:58:10

标签: node.js twitter https websocket get

我想从我的Node服务器向Twitter发出GET请求,解析响应数据,并通过websocket(ws,而不是wss)连接发送。一切正常 - 除了30秒后(我计时,它总是30 +/- 1秒),套接字连接挂起,我得到以下错误堆栈:

    Error: socket hang up
    at createHangUpError (_http_client.js:200:15)
    at TLSSocket.socketOnEnd (_http_client.js:292:23)
    at emitNone (events.js:72:20)
    at TLSSocket.emit (events.js:166:7)
    at endReadableNT (_stream_readable.js:905:12)
    at nextTickCallbackWith2Args (node.js:442:9)
    at process._tickCallback (node.js:356:17)

我一直在使用与Twitter的公共流相同的服务器设计,它运作良好。只有在实现GET请求时才会发生挂断。

到目前为止,我已经尝试了以下解决方案:

  • 限制请求传入速率waaaay在Twitter查询uri编码字符串中以低计数值下降;即使有一条推文发回给我,仍然会在约30秒后发生超时
  • keepAliveAgent设置为我的GET请求选项
  • 尝试为请求手动构建(无npm模块)代理
  • 设置KeepAliveIntervalkeepaliveGracePeriod,           和套接字服务器上的dropConnectionOnKeepaliveTimeout
  • 和一堆Node newbish thing

一切都无济于事。该应用程序保持精美的工作30秒;然后,它就会挂掉。

我的下一个主角:Twitter要求通过HTTPS发送仅应用程序身份验证的请求。我没有在我的代码中为不同的安全级别做出任何规定。我现在要对此进行跟进 - 看看SO社区是否有任何想法。非常感谢您提供的任何帮助!

以下是代码,简要介绍:

// Initialize basic server for the web socket requests
var handShakeServer = http.createServer(function(request, response) {
  console.log((new Date()) + ' Received request for ' + request.url);
  response.writeHead(404);
  response.end();
});

handShakeServer.listen(8080, function() {
  console.log((new Date()) + ' Socket server is listening on port 8080');
});

// Initialize the socket server itself.
var socketServer = new WebSocketServer({
  httpServer: handShakeServer,
  autoAcceptConnections: false,
  keepAliveInterval: (3600 * 1000),
  dropConnectionOnKeepaliveTimeout: false
});

// On request, listen for messages.
socketServer.on('request', function(request) {
  
  // Initialize connection from verified origin
  var connection = request.accept('echo-protocol', request.origin);
  
  // On message (search params from client), query Twitter.
  connection.on('message', function(message) {
    
    // BEARER_ACCESS_TOKEN is for Twitter's application-only authentication
    var options = {
      'path': '/1.1/search/tweets.json?q=stuff',
      'hostname': 'api.twitter.com',
      'method': 'GET',
      'headers': {
        'Authorization': ('Bearer ' + process.env.BEARER_ACCESS_TOKEN),
        'Accept': '*/*'
      },
      'agent': agent,
      'port': 443,
    };
    
    // Query twitter via HTTPS GET, listen for response
    var req = new https.request(options, function(res) {
      var responseString = '';

      // On data, concatenate the chunks into a whole JSON object
      res.on('data', function(tweet) {
        responseString += tweet;
      });
      
      // On completion of request, send data to be analyzed. 
      res.on('end', function() {

        // Once returned, send data to client through socket connection.
        var result = doSomeAnalysis(JSON.parse(responseString));
        connection.sendUTF(JSON.stringify(result));

      });
    });

    // The https request is done; terminate it. 
    req.end();
  });
});

此外,在Web套接字客户端,我有:

    client.connect('ws://localhost:8080/', 'echo-protocol', 'twitterQuery');

以下是我的server.js中的相关模块:

var util             = require('util');
var https            = require('https');
var http             = require('http');
var WebSocketServer  = require('websocket').server;
var HttpsAgent       = require('agentkeepalive').HttpsAgent;

1 个答案:

答案 0 :(得分:0)

确定!原来的HTTPS兼容性不会导致挂断。当我完全将websocket连接逻辑与Twitter请求逻辑分离并将console.log虚函数放在他们曾经重叠的地方时,Twitter查询工作正常,但是websocket连接让我挂起了挂断错误,就像以前一样 - 总是在30之后秒,并且始终无论通过连接发送了多少数据。

修复:手动设置ping / pong度量,以两种方式之一(或两种方式,以获得额外冗余)方式:

//SERVER SIDE: 

    // Option 1: Use the npm module's event 'ping'
    connection.on('ping', function(data){
        console.log('Server: ping received at: ' + (new Date()))        
    })

    // Option 2: Use the more generalized event 'message', look for your
    // custom 'ping' message
    connection.on('message', function(message){ 
        console.log("Socket server received message from client.")
        if (message.utf8Data == 'ping'){
           console.log('pong!')
        }
    })

//CLIENT SIDE: 
    setInterval(function(){              
        if (connection.connected){
            // To match Option 1 above, use this: 
            connection.ping();
            // To match Option 2 above, use this: 
            connection.sendUTF('ping');
        }
    }, 19900)

    connection.on('pong', function(){
        console.log('Client: pong received at: ' + (new Date()) + '\n')
    })

所以,最后,一个非常基本的修复。我不明白为什么连接需要这些保持活着的ping,因为Twitter响应在它退出我的分析功能后立即通过连接以~1秒的间隔通过管道传输,保持连接非常活跃(但不会过载) )。请参阅我的原始帖子,了解这种情况:

// Once returned, send data to client through socket connection.
var result = doSomeAnalysis(JSON.parse(responseString));
connection.sendUTF(JSON.stringify(result));

可能是因为没有'pong'被发送回服务器,因此,即使websocket连接保持其数据飞出,它也不知道它的接收端是否仍然是活动的。但是 - 为什么我的流媒体活动不需要相同的衡量标准?它通过相同的频道工作,一旦流媒体开始就不会从客户端收到任何数据(没有'pong'),并且将永久地继续(直到Google地理编码关闭我,即:)。

我想,通过推断,默认情况下必须在流中存在一些保持活动的ponging,并且我需要手动将其添加到GET请求中,因为我本质上是将批处理响应绑定到流出,小块的小块,因为返回退出我的分析函数。

冷却。无论如何,我以为我会留下这个(太冗长)的帖子,以防任何人因使用大数据块的GET请求而被挂起(双关语!),然后通过您的网络套接字连接进行虚假流媒体传输。组合确实很好用,解决了这个问题。