Node.js 木偶演员与快速路由器节点JS的并行性。如何在保持并发性的同时在路由之间传递页面

Node.js 木偶演员与快速路由器节点JS的并行性。如何在保持并发性的同时在路由之间传递页面,node.js,express,http,puppeteer,express-router,Node.js,Express,Http,Puppeteer,Express Router,是否有可能以某种方式将页面和浏览器从一个路由转移到另一个路由,同时保持Puppeter并发性。如果全局设置变量,则页面和浏览器将被覆盖,多任务处理将不起作用。一种方法是创建一个闭包,该闭包返回将解析为相同页面和浏览器实例的承诺。由于HTTP是无状态的,我假设您有一些会话/身份验证管理系统,它将用户的会话与Puppeter浏览器实例相关联 为了制作一个完整的、可运行的示例,我简化了您的路由,并添加了一个简单的令牌管理系统来将用户与会话相关联,但我认为您在将其调整到您的用例时不会遇到问题 app.p

是否有可能以某种方式将页面和浏览器从一个路由转移到另一个路由,同时保持Puppeter并发性。如果全局设置变量,则页面和浏览器将被覆盖,多任务处理将不起作用。

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

为了制作一个完整的、可运行的示例,我简化了您的路由,并添加了一个简单的令牌管理系统来将用户与会话相关联,但我认为您在将其调整到您的用例时不会遇到问题

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();
}});
从客户的角度看示例用法:

$curl localhost:8000/start?令牌=1
好啊
$curl'本地主机:8000/导航到=https://stackoverflow.com/questions/66935883&token=1'
好啊
$curl localhost:8000/内容?令牌=1 | grep'apsenT'
阿森特
是此站点的新贡献者。在要求澄清、评论和回答时要小心。
是一个新的贡献者。友好点,看看我们的网站。
$curl localhost:8000/kill?令牌=1
好啊
您可以看到与令牌1关联的客户端已跨多个路由持久化了单个浏览器会话。其他客户端可以启动浏览器会话并同时操作它们

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


使用的软件包:express ^4.17.1,Puppeter ^8.0.0。

欢迎使用SO!我不确定术语“并行性”、“并发性”和“多任务处理”是否是您在这里寻找的。节点是单线程、异步事件驱动的。我想你的意思是你想在不阻塞事件循环的情况下跨路由维护单个浏览器实例,我在这个假设下回答。如果你的意图是其他的,请随时澄清。
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"))
;