2012-07-22 1 views
6

나는 PhantomJS에서 server.listen(...)을 사용하고 있습니다. 나는 이것이 실험적이며 생산에 사용되어서는 안된다는 것을 알고 있습니다. 나는 URL을위한 스크린 샷을 생성하는 간단한 스크린 샷 - 서버를 사용하고 있습니다. 그것은 PhantomJS로 놀기 위해 사용하고있는 장난감 프로젝트입니다. 특히 장기 실행 요청과 관련하여 response 개체를 사용할 수없는 경우 문제가 발생했습니다. 여기에 내 코드에서 관련 조각입니다PhantomJS : server.listen (...)에서 응답 객체가 살아 있는지 확인

var service = server.listen(8080, function (request, response) { 

    response.statusCode = 200; 

    if (loglevel === level.VERBOSE) { 
     log(request); 
    } else { 
     console.log("Incoming request with querystring:", request.url); 
    } 

    var params = parseQueryString(request.url); 
    if (params[screenshotOptions.ACTION] === action.SCREENSHOT) { 
     getScreenshot(params, function (screenshot) { 

      response.headers["success"] = screenshot.success; //<-- here is where I get the error that response.headers is unavailable. Execution pretty much stops at that point for that particular request. 
      response.headers["message"] = screenshot.message; 

      if (screenshot.success) { 
       response.write(screenshot.base64); 
      } else { 
       response.write("<html><body>There were errors!<br /><br />"); 
       response.write(screenshot.message.replace(/\n/g, "<br />")); 
       response.write("</body></html>"); 
      } 

      response.close(); 
     }); 
    } else { 
     response.write("<html><body><h1>Welcome to the screenshot server!</h1></body></html>") 
     response.close(); 
    } 
}); 

getScreenshot 웹 페이지를 엽니 다 WebPage.open(...) 함수를 사용하는 비동기 방법은; 이 함수는 비동기 적입니다. 그래서 무슨 일이 일어나는 것입니까? getScreenshot에 인수로 전달 된 콜백이 마침내 호출되면 response 개체가 이미 삭제 된 것처럼 보입니다. 나는 기본적으로 PhantomJS에서 다음과 같은 오류와 끝까지 :

Error: cannot access member `headers' of deleted QObject 

내가 요청 시간이 초과 때문에 연결이 닫혀 있기 때문입니다 생각합니다. 설명서에는 연결이 열려 있는지 확인하기 위해 적어도 한 번 이상 response.write("")을 호출하는 내용이 나와 있습니다. 나는 server.listen(...)의 시작 부분에 response.write("")을 호출 해 보았고 나는 심지어 setInterval(...)을 사용하여 매 500 밀리 초마다 response.write("")을 수행했다. (나는 심지어 그것을 50 이하로 낮췄다.) 나는 또한 일단 내가 끝내면 그 간격을 확실하게했다. 그러나, 나는 아직도이 문제를 얻는 것처럼 보입니다.

웹 서버 모듈을 더욱 강력하게 만들 때까지 처리해야 할이게 뭔가요? 아니면 주위에 방법이 있습니까?

답변

8

나는 이것을 알아낼 수 있었다. 특정 페이지를 WebPage.open (예 : http://fark.comhttp://cnn.com)으로로드하는 동안 복수 onLoadFinished 이벤트가 발생하는 것으로 보입니다. 따라서 WebPage.open의 콜백이 여러 번 호출됩니다. 그래서 어떤 일이 발생하면 컨트롤이 호출 함수로 돌아 왔을 때 이미 응답을 닫았으므로 response 객체는 더 이상 유효하지 않습니다. WebPage.open 함수가 호출되기 전에 플래그를 만드는 방법으로이 문제를 해결했습니다. 콜백 내에서 플래그의 상태를 확인하여 이전에 onLoadFinished 이벤트가 발생했는지 확인합니다. 일단 내가 WebPage.open 콜백 내부에서해야 할 일이 있으면 처리를 마친 것을 보여주기 위해 플래그를 업데이트합니다. 이 방법은 (적어도 내 코드의 컨텍스트에서) onLoadFinished 이벤트는 더 이상 서비스되지 않습니다.

+1

또한 서버 킵 얼라이브를 false로 변경했는데 너무 도움이 된 것처럼 보였습니다 .-service = server.listen (포트, {keepAlive : false}, function (request, response) {... – chrismarx

+1

감사합니다. 어떻게 문제를 해결했는지 세분화합니다.그냥 똑같은 문제에 부딪 혔습니다. –

+0

위 Chris의 코멘트 - 적어도 PhantomJS 1.9.7부터, ['keepAlive'의 기본값은'false'입니다] (https://github.com/ariya/phantomjs/blob/1.9.7/src/webserver.cpp) # L116-L118). – Whymarrh

0

(영업 가능성이 1.6.1 또는 그 이상을 언급하는 동안 다음이 PhantomJS 1.9.7을 의미합니다.) 여러 onLoadFinished 이벤트가 해고되고 있다는 이벤트에서

을, 당신은 page.open()을 사용할 수 있습니다 대신 onLoadFinished을 청취하십시오. page.open()을 사용하면 콜백을 한 번만 호출 할 수 있도록 처리기를 개인 처리기로 래핑합니다. the source에서

:

definePageSignalHandler(page, handlers, "_onPageOpenFinished", "loadFinished"); 
page.open = function (url, arg1, arg2, arg3, arg4) { 
    var thisPage = this; 
    if (arguments.length === 1) { 
     this.openUrl(url, 'get', this.settings); 
     return; 
    } 
    else if (arguments.length === 2 && typeof arg1 === 'function') { 
     this._onPageOpenFinished = function() { 
      thisPage._onPageOpenFinished = null; 
      arg1.apply(thisPage, arguments); 
     } 
     this.openUrl(url, 'get', this.settings); 
     return; 
    } 
// ... Truncated for brevity 

이 기능은 공식 API의 일부로 노출, 완전히 다른 대답과 동일합니다.

관련 문제