Node.js:给定URL数组,确定哪些是有效的

时间:2016-06-18 17:50:21

标签: node.js http asynchronous response

我使用节点http模块进行全面清理,但遇到了一些麻烦。

这里的最终目标是获取一个巨大的网址列表,找出哪些是有效的,然后为某些数据抓取这些网页。因此,第一步是确定一个URL是否有效,这个简单的练习令我困惑。

说我们有一个数组allURLs:

["www.yahoo.com", "www.stackoverflow.com", "www.sdfhksdjfksjdhg.net"]

目标是迭代这个数组,向每个数组发出一个get请求,如果响应进来,将链接添加到workingURL列表(现在只是另一个数组),否则它会转到一个brokenURLs列表。

var workingURLs = [];
var brokenURLs = [];
for (var i = 0; i < allURLs.length; i++) {
  var url = allURLs[i];
  var req = http.get(url, function (res) {
    if (res) {
      workingURLs.push(?????);  // How to derive URL from response?
    }
  });

  req.on('error', function (e) {
    brokenURLs.push(e.host);
  });
}

我不知道的是如何从请求/响应对象本身正确获取url,或者真正如何构造这种异步代码 - 因为再次,我是一个nodejs scrub:(

对于大多数使用res.headers.location的网站都有效,但有时候标题没有这个属性,以后会对我造成问题。此外,我已经尝试过控制台记录响应对象本身,这是一个混乱和毫无结果的努力

我已经尝试将url变量推送到workingURLs,但是当任何响应返回时会触发push,for循环已经结束,url永远指向allURLs数组的最后一个元素。

感谢任何可以提供帮助的人

2 个答案:

答案 0 :(得分:3)

您需要关闭url值才能访问它并保护它免受下一次循环迭代的更改 例如:

(function(url){
  // use url here
})(allUrls[i]);

最简单的解决方案是使用forEach代替for

allURLs.forEach(function(url){
  //....
});

Promisified解决方案可让您在工作完成时获得一些时间:

    var http = require('http');
    var allURLs = [
      "http://www.yahoo.com/",
      "http://www.stackoverflow.com/",
      "http://www.sdfhksdjfksjdhg.net/"
    ];
    var workingURLs = [];
    var brokenURLs = [];
    var promises = allURLs.map(url => validateUrl(url)
      .then(res => (res?workingURLs:brokenURLs).push(url)));
    Promise.all(promises).then(() => {
      console.log(workingURLs, brokenURLs);
    });
    // ----
    function validateUrl(url) {
      return new Promise((ok, fail) => {
        http.get(url, res => return ok(res.statusCode == 200))
          .on('error', e => ok(false));
      });
    }

// Prevent nodejs from exit, don't need if any server listen.
var t = setTimeout(() => { console.log('Time is over'); }, 1000).ref();

答案 1 :(得分:1)

你可以使用这样的东西(未经测试):

const arr = ["", "/a", "", ""];

Promise.all(arr.map(fetch)
.then(responses=>responses.filter(res=> res.ok).map(res=>res.url))
.then(workingUrls=>{
  console.log(workingUrls);
  console.log(arr.filter(url=> workingUrls.indexOf(url) == -1 ))
});

<强> EDITED

Working fiddle(请注意,由于跨域名,您无法在浏览器中请求其他网站。)

使用@vp_arth建议更新

const arr = ["/", "/a", "/", "/"];
let working=[], notWorking=[],
    find = url=> fetch(url)
    .then(res=> res.ok ? 
        working.push(res.url) && res : notWorking.push(res.url) && res);

Promise.all(arr.map(find))
.then(responses=>{
    console.log('woking', working, 'notWorking', notWorking);
    /* Do whatever with the responses if needed */
});

Fiddle