gpt4 book ai didi

node.js - Puppeteer 与 Express Router Node JS 的并行性。如何在保持并发的情况下在路由之间传递页面

转载 作者:行者123 更新时间:2023-12-04 03:35:51 29 4
gpt4 key购买 nike

app.post('/api/auth/check', async (req, res) => {
try {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto(
'https://www.google.com'
);
res.json({message: 'Success'})
} catch (e) {
console.log(e);
res.status(500).json({ message: 'Error' });
}});

app.post('/api/auth/register', async (req, res) => {
console.log('register');
// Here i'm need to transfer the current user session (page and browser) and then perform actions on the same page.
await page.waitForTimeout(1000);
await browser.close();
}});

是否有可能以某种方式将页面和浏览器从一个路由转移到另一个路由,同时保持 puppeteer 并发。如果全局设置该变量,则页面和浏览器将被覆盖,多任务将无法运行。

最佳答案

一种方法是创建一个闭包,该闭包返回将解析为相同页面和浏览器实例的 promise 。由于 HTTP 是无状态的,我假设您有一些 session /身份验证管理系统将用户的 session 与 Puppeteer 浏览器实例相关联。

为了制作一个完整的、可运行的示例,我稍微简化了您的路线并添加了一个朴素的 token 管理系统以将用户与 session 相关联,但我认为您在调整它以适应您的需求时不会遇到问题用例。

const express = require("express");
const puppeteer = require("puppeteer");

// https://stackoverflow.com/questions/51391080/handling-errors-in-express-async-middleware
const asyncHandler = fn => (req, res, next) =>
Promise.resolve(fn(req, res, next)).catch(next)
;
const startPuppeteerSession = async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
return {browser, page};
};
const sessions = {};

express()
.use((req, res, next) =>
req.query.token === undefined ? res.sendStatus(401) : next()
)
.get("/start", asyncHandler(async (req, res) => {
sessions[req.query.token] = await startPuppeteerSession();
res.sendStatus(200);
}))
.get("/navigate", asyncHandler(async (req, res) => {
const page = await sessions[req.query.token].page;
await page.goto(req.query.to || "http://www.example.com");
res.sendStatus(200);
}))
.get("/content", asyncHandler(async (req, res) => {
const page = await sessions[req.query.token].page;
res.send(await page.content());
}))
.get("/kill", asyncHandler(async (req, res) => {
const browser = await sessions[req.query.token].browser;
await browser.close();
delete sessions[req.query.token];
res.sendStatus(200);
}))
.use((err, req, res, next) => res.sendStatus(500))
.listen(8000, () => console.log("listening on port 8000"))
;

从客户的角度来看的示例用法:

$ curl localhost:8000/start?token=1
OK
$ curl 'localhost:8000/navigate?to=https://stackoverflow.com/questions/66935883&token=1'
OK
$ curl localhost:8000/content?token=1 | grep 'apsenT'
<a href="/users/15547056/apsent">apsenT</a><span class="d-none" itemprop="name">apsenT</span>
<a href="/users/15547056/apsent">apsenT</a> is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
<a href="/users/15547056/apsent">apsenT</a> is a new contributor. Be nice, and check out our <a href="/conduct">Code of Conduct</a>.
$ curl localhost:8000/kill?token=1
OK

您可以看到与 token 1 关联的客户端已跨多个路由保留了一个浏览器 session 。其他客户端可以启动浏览器 session 并同时操作它们。

重申一下,这只是跨路由共享 Puppeteer 浏览器实例的概念验证。使用上面的代码,用户可以向 start 路由发送垃圾邮件并创建浏览器,直到服务器崩溃,因此如果没有真正的身份验证和 session 管理/错误处理,这完全不适合生产。

使用的包:express ^4.17.1,puppeteer ^8.0.0。

关于node.js - Puppeteer 与 Express Router Node JS 的并行性。如何在保持并发的情况下在路由之间传递页面,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66935883/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com