admin管理员组文章数量:1399805
I'm using server.listen(...)
from PhantomJS. I realize that it is largely experimental and that it shouldn't be used in production. I'm using it for a simple screenshot-server that accepts generates screenshots for a URL; it's a toy project that I'm using to play around with PhantomJS. I've noticed an issue with long-running requests in particular, where the response
object is unavailable. Here are the relevant snippets from my code:
var service = server.listen(8080, function (request, response) {
response.statusCode = 200;
if (loglevel === level.VERBOSE) {
log(request);
} else {
console.log("Ining 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>Wele to the screenshot server!</h1></body></html>")
response.close();
}
});
getScreenshot
is an asynchronous method that uses the WebPage.open(...)
function to open a webpage; this function is also asynchronous. So what seems to be happening is that when the callback that is passed in as an argument to getScreenshot
is finally called, it appears that the response
object has already been deleted. I basically end up with the following error from PhantomJS:
Error: cannot access member `headers' of deleted QObject
I believe this is because the request times out and so the connection is closed. The documentation mentions calling response.write("")
at least once to ensure that the connection stays open. I tried calling response.write("")
at the beginning of server.listen(...)
and I even tried a pretty hacky solution where I used setInterval(...)
to perform a response.write("")
every 500 milliseconds (I even lowered it down to as little as 50). I also made sure to clear the interval once I was done. However, I still seem to get this issue.
Is this something that I'm just going to have to deal with until they make the webserver module more robust? Or is there a way around it?
I'm using server.listen(...)
from PhantomJS. I realize that it is largely experimental and that it shouldn't be used in production. I'm using it for a simple screenshot-server that accepts generates screenshots for a URL; it's a toy project that I'm using to play around with PhantomJS. I've noticed an issue with long-running requests in particular, where the response
object is unavailable. Here are the relevant snippets from my code:
var service = server.listen(8080, function (request, response) {
response.statusCode = 200;
if (loglevel === level.VERBOSE) {
log(request);
} else {
console.log("Ining 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>Wele to the screenshot server!</h1></body></html>")
response.close();
}
});
getScreenshot
is an asynchronous method that uses the WebPage.open(...)
function to open a webpage; this function is also asynchronous. So what seems to be happening is that when the callback that is passed in as an argument to getScreenshot
is finally called, it appears that the response
object has already been deleted. I basically end up with the following error from PhantomJS:
Error: cannot access member `headers' of deleted QObject
I believe this is because the request times out and so the connection is closed. The documentation mentions calling response.write("")
at least once to ensure that the connection stays open. I tried calling response.write("")
at the beginning of server.listen(...)
and I even tried a pretty hacky solution where I used setInterval(...)
to perform a response.write("")
every 500 milliseconds (I even lowered it down to as little as 50). I also made sure to clear the interval once I was done. However, I still seem to get this issue.
Is this something that I'm just going to have to deal with until they make the webserver module more robust? Or is there a way around it?
Share Improve this question asked Jul 22, 2012 at 5:39 Vivin PaliathVivin Paliath 95.6k42 gold badges230 silver badges301 bronze badges2 Answers
Reset to default 8I was able to figure this out. It appears that while loading certain pages with WebPage.open
(for example http://fark.
and http://cnn.
) multiple onLoadFinished
events are fired. This results in the callback in WebPage.open
being called multiple times. So what happens is that when control es back to the calling function, I've already closed the response and so the response
object is no-longer valid. I fixed this by using creating a flag before the WebPage.open
function is called. Inside the callback, I check the status of the flag to see if I've already encountered a previous onLoadFinished
event. Once I am with whatever I have to do inside the WebPage.open
callback, I update the flag to show that I've finished processing. This way spurious (at least in the context of my code) onLoadFinished
events are no-longer serviced.
(Note that the following refers to PhantomJS 1.9.7 while the OP was likely referring to 1.6.1 or older.)
In the event that multiple onLoadFinished
events are being fired, you can use page.open()
instead of listening for onLoadFinished
yourself. Using page.open()
will wrap your handler in a private handler to ensure that your callback is only called once.
From 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
This functionality is exactly the same as the other answer, exposed as part of the official API.
本文标签: javascriptPhantomJS Ensuring that the response object stays alive in serverlisten()Stack Overflow
版权声明:本文标题:javascript - PhantomJS: Ensuring that the response object stays alive in server.listen(...) - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744126567a2591978.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论