Here is a simplified version of my code:
var page;
var launched = false;
app.post("/test", async(req, res) => {
if ( launched == false ) {
const browser = await puppeteer.launch({
headless: true, /* I've tried with "new" and false too */
});
page = await browser.newPage();
var desiredUrl = "url here";
await page.goto(desiredUrl);
/* Stream data from the page */
await page.exposeFunction('writeData', (data) => {
console.log("Writing data");
res.write(data);
});
/* End stream */
await page.exposeFunction('endStream', () => {
console.log("End stream");
res.end();
});
launched = true;
}
await page.evaluate(async ()=>{
var output = await fetch("/endpoint_here", {
"headers": {
/* headers here */
},
});
var reader = output.body.getReader();
while (true) {
var { done, value } = await reader.read();
if (done) {
window.endStream();
return;
}
var decoder = new TextDecoder();
var decodedData = decoder.decode(value);
window.writeData(decodedData);
}
});
})
However, this doesn't work. What I've tried is listed below:
res doesn't work inside of page.evaluate(). I've tried sending res into the page.evaluate(), but it breaks the code.
I've tried using page.exposeFunction() and doing the res.write (and res.end() ) there, and it worked but only for the first time. The second time (and every time after that) where I sent the post request, the code ran properly (it did the console.logs in those functions) except it didn't do the res.write() and res.end() at all.
I've even tried making it update a global variable inside the page.evaluate() using an exposed function, detecting the changes in that variable using a proxy and doing res.write() to write the data, but that also broke after the first post request.
The only fix to this strange problem of it only working the first time is restarting the program, which obviously isn't a solution.
I've also tried logging the stream data to the console in the page and used page.on('console') to res.write() the data back to the client. This worked perfectly with one request at a time. However, when there were multiple simultaneous requests to the endpoint "/test", it would write the response to both clients instead of just the one that initiated the request.
The only thing that DID work was just returning the response from the fetch after it ended without streaming it. However, I want it to be streamed.
I'm stuck and have no idea what to do, so any help would be greatly appreciated.
res
is only available in Node, not in the browser. Return the data back to Node withexposeFunction
and callres.end()
andres.write()
in Node. I guess you tried this--but this is the correct approach, so if you could update your code to show that attempt, it's better to debug that than trying to callres.write()
in the browser, which is definitely not going to work. Please also share the POST endpoint, or a reproducible representation of the page you're automating, so that it's possible to debug the "not working after the first time" situation using runnable code. Thanks. – Consentaneous