2016-06-18 4 views
2

노드 http 모듈을 사용하여 전체 제거 중이며 약간의 문제가 있습니다.Node.js : 주어진 URL 배열로 유효 범위를 결정하십시오.

궁극적 인 목표는 엄청난 수의 URL 목록을 확인하고 유효한지 파악한 다음 특정 데이터에 대해 해당 페이지를 긁는 것입니다. URL이 유효하고이 간단한 운동이 저를 당황하게하는 경우 단계 1은 알아 내고 있습니다.

우리가 배열 allURLs이 있다고 :

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

목표는,이 배열을 반복 각각에 GET 요청을하고 응답이 오면, 지금은 (workingURLs의 목록에 대한 링크를 추가하는 것입니다 또 다른 배열), 그렇지 않으면 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 스크럽이기 때문에 :(

res.headers.location을 사용하는 대부분의 웹 사이트에서는 헤더가이 속성을 갖고 있지 않아 나중에 나에게 문제가 발생할 수 있습니다. 또한 응답 객체 자체를 로깅하는 콘솔을 시도했지만 지저분하고 열매없는 노력

나는 url 변수를 workingURLs에 넣으려고했으나 아무 때 나 응답을 받았다. 푸시를 트리거하면 for 루프는 이미 끝났고 url은 allURL 배열의 마지막 요소를 영원히 가리키고 있습니다.

답변

3

을 도울 수있는 사람에게

덕분에 당신은에 액세스 할 수 있으며 다음 루프 반복에 변화로부터 보호하기 위해 폐쇄 URL 값이 필요합니다. 예를 들어
: 이것에 대한

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

가장 간단한 해결책은 forEach 대신 for 사용된다.

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(); 
+0

* "당신은에 액세스 할 수 있도록 폐쇄 URL 값이 필요합니다."* 맞습니다 아니다 업데이트되었습니다. 'http.get (...)'콜백은 이미 클로저입니다. OP가 필요로하는 것은 반복마다 새로운 범위를 만드는 것인데, 이는 forEach가하는 일입니다. –

+0

'url 값을 닫으려고 '하는 것은'각 반복마다 일부 범위에 URL 값을 캡슐화'하는 것을 의미합니다. 'http.get' 콜백은 초기 URL과 아무 관련이 없습니다. –

+0

가장 좋은 대답은 두 대답을 합친 것입니다. 하나는 상태를 검사하고, 하나는 .on ('error')를 처리합니다. – Madd0g

1

는이 같은 (테스트되지 않음)를 사용할 수 있습니다 :

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

Promisified 솔루션은 작업이 완료되면 당신이 순간을 얻을 수 있습니다

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

편집을

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

+1

너무 편한'fetch' API입니다. 그냥'arr.map (fetch)'로 쓸 수 있습니다. 모든 200-299 상태에 대해서도 부울'res.ok'가 있습니다. –

+0

이 예제에서 가져 오기는 약속을 반환합니까? (이 API에 익숙하지 않음) 어떤 경우에도 도움을 주셔서 감사합니다. – nick

+0

예! 가져 오기 약속을 반환합니다. 더 많은 예제는 https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch에서 확인하십시오. –

관련 문제