簡體   English   中英

從Node.JS中的兩個網站請求RSS提要

[英]Requesting RSS feeds from two web sites in Node.JS

我有一個Node.JS服務器,它從兩個Web服務器請求數據: bbc.co.uksky.com 然后解析RSS提要,並且用戶看到兩個列表:來自BBC和來自天空。

這是代碼。

var feed = require('feed-read');
var http = require('http');
var async = require('async');
var request = require('request');

var LIMIT = 10;
var UNABLE_TO_CONNECT = "Unable to connect.";
var BBC_URL = 'http://feeds.bbci.co.uk/news/rss.xml';
var SKY_URL = 'http://news.sky.com/feeds/rss/home.xml';

var server = http.createServer(onRequest);
server.listen(9000);

function onRequest(req, res) {
    res.writeHead(200, {
        'Content-Type' : 'text/html; charset=utf-8'
    });

    async.parallel([ function(callback) {
        feed(BBC_URL, onRssFetched);
        // TODO: where to call callback()?
    }, function(callback) {
        feed(SKY_URL, onRssFetched);
        // TODO: where to call callback()?
    } ], function done(err, results) {
        console.log("Done");
        if (err) {
            throw err;
        }
    });
}

function onRssFetched(err, articles) {
    console.log("RSS fetched");
    var html = [];
    if (err) {
        html.push("<p>", UNABLE_TO_CONNECT = "</p>");
    } else {
        html.push("<ol>");
        var i = 0;
        articles.forEach(function(entry) {
            if (i == LIMIT) {
                return;
            }
            html.push("<li><a href='" + entry.link + "'>" + entry.title
                    + "</a></li>");
            i++;
        });
    }
    console.log(html.join(""));
}

現在我不知道如何將結果添加到網頁。 如果我調用callback()調用后立即feed的方法, callback()將無需等到執行feed已完成其工作。 另一方面,我無法將callback傳遞給feed 也許這種方法是錯誤的,我還需要一些其他模塊來進行RSS解析。

@Maksim我知道您的原始問題包括異步模塊,但提出了另一種選擇:

為什么不將 每篇文章 流式傳輸到客戶端,而不是在發送響應之前等待所有 RSS源返回...?

通過使用async.parallel,您告訴節點:

等到我們得到 所有 這些新聞服務 的回復
並且只有 這樣 (將文章組合成) 對客戶 單一 回應 ...“

當您等待所有響應(來自RSS新聞服務)時,這會占用每個連接客戶端的內存...... 浪費

所以我寫了我的答案而不訴諸異步
並且,而不是等待年齡 (而async將所有的feed合並為一個),
一旦第一個 RSS提要返回,客戶端就會看到新聞!

var feed = require('feed-read'),  // require the feed-read module
    http = require("http"),
    urls = [
        "http://feeds.bbci.co.uk/news/rss.xml",
        "http://news.sky.com/feeds/rss/home.xml",
        "http://www.techmeme.com/feed.xml"
    ]; // Example RSS Feeds

http.createServer(function (req, res) { 
    // send basic http headers to client
    res.writeHead(200, {
        "Content-Type": "text/html",
        "Transfer-Encoding": "chunked"
    });

    // setup simple html page:
    res.write("<html>\n<head>\n<title>RSS Feeds</title>\n</head>\n<body>");

    // loop through our list of RSS feed urls
    for (var j = 0; j < urls.length; j++) {

        // fetch rss feed for the url:
        feed(urls[j], function(err, articles) {

            // loop through the list of articles returned
            for (var i = 0; i < articles.length; i++) {

                // stream article title (and what ever else you want) to client
                res.write("<h3>"+articles[i].title +"</h3>"); 

                // check we have reached the end of our list of articles & urls
                if( i === articles.length-1 && j === urls.length-1) {
                    res.end("</body>\n</html>"); // end http response
                } // else still have rss urls to check
            } //  end inner for loop
        }); // end call to feed (feed-read) method
    } // end urls for loop
}).listen(9000);

主要優勢

  • 連接到您應用的人會看到新聞/結果更快 (幾乎立即!)
  • 應用程序使用更少的內存
  • 添加新RSS新聞源時,您無需編輯/更新任何代碼

有關此解決方案的更多詳細信息/說明
請參閱: https//github.com/nelsonic/node-parse-rss

不,你不需要另一個圖書館。 但您需要做的是將callback交給您的feed函數而不是onRssFetched 這樣,使用result變量將單個RSS提要移交給async.parallel調用中的最終回調。

在這個變量中,您可以同時訪問這兩個RSS源,並且可以對它們執行任何操作。

所以,基本上你的邏輯需要是:

async.parallel({
  bbc: function (callback) {
    feed(BBC_URL, callback);
  },
  sky: function (callback) {
    feed(SKY_URL, callback);
  }
}, function (err, result) {
  if (err) {
    // Somewhere, something went wrong…
  }

  var rssBbc = result.bbc,
      rssSky = result.sky;

  // Merge the two feeds or deliver them to the client or do
  // whatever you want to do with them.
});

就是這樣:-)。

為了放大@nelsonic的答案(足以讓我覺得這保證了它自己的答案), feed-parse已經異步處理。 從本質上講,它仍然在http.request上運行。 如果你查看代碼,你會看到你甚至可以直接傳遞一個URL數組,它會遍歷它們,但是它使用了更多的“async.eachSeries”方法,其中下一個調用只發生在前一個調用之后完成,看起來不是你想要的。

如果你真的想在處理之前等待調用先完成,那么你最好異步緩沖數據,然后使用下划線的_.after()在所有URL完成后運行。

但是很可能,你真正想做的事情(除非你只是尋找一個嘗試異步的例子)是@ nelsonic的回答。

理想情況下,我會流式傳輸rss數據,而不是聚合在內存中。 @nelsonic已經解釋了解決這個問題的正確方法。

不過,如果我們要讓您的代碼運行,請考慮以下代碼:

var util = require('util');
var http = require('http');
var async = require('async');
var feed = require('feed-read');
var request = require('request');

var LIMIT = 10;
var UNABLE_TO_CONNECT = 'Unable to connect.';
var BBC_URL = 'http://feeds.bbci.co.uk/news/rss.xml';
var SKY_URL = 'http://news.sky.com/feeds/rss/home.xml';

var server = http.createServer(onRequest);
server.listen(9000);

function onRequest(req, res) {
  util.log('Request recieved!');
  res.writeHead(200, {
    'Content-Type': 'text/html; charset=utf-8'
  });

  async.parallel({
    bbc: function (callback) {
      feed(BBC_URL, function (err, articles) {
        var html = onRssFetched(err, articles);
        callback(err, html);
      });
    },
    sky: function (callback) {
      feed(SKY_URL, function (err, articles) {
        var html = onRssFetched(err, articles);
        callback(err, html);
      });
    }
  }, done);

  function done(err, results) {
    util.log('Received results: ' + Object.keys(results).join(','));
    if (!err && results) {
      var entry, html;
      for (entry in results) {
        html = results[entry];
        res.write(html.join(''));
      }
      util.log('Send complete!');
      res.end();
    } else {
      console.log(err || 'no data in results');
      res.end('Unable to process your request');
    }
  }
}

function onRssFetched(err, articles) {
  // limit number of articles;
  articles = articles.slice(0, LIMIT);

  var html = [];
  if (err) {
    html.push('<p>', UNABLE_TO_CONNECT = '</p>');
  } else {
    html.push('<ol>');
    articles.forEach(function (entry) {
      html.push('<li><a href="' + entry.link + '">' + entry.title + '</a></li>');
    });

    html.push('</ol>');
  }
  return html;
}

// -- Test Code ---------------------------------------------------------
if (require.main === module) {
  (function () {
    var req, res = {
        writeHead: console.log,
        write: console.log,
        end: console.log
      };
    // onRequest(req, res);
  })();
}

如果您遇到任何問題,請告訴我。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM