
字节笔记本
2026年10月7日 · 约 3 分钟读完
错误处理注册在路由后面
原函数用 puppeteer-core 启动浏览器,executablePath 指向苹果系统里 Google Chrome 的应用路径,无头为真。打开地址时 waitUntil 是 networkidle0。用 $eval 取 #page-content 的 innerText。最后在 finally 里关闭浏览器。示例调用写了一个具体网页地址。那个地址带有签名一类的参数,不应该出现在公开说明里。
中间件的顺序决定包得住谁
改成 Koa 之后,跨域先挂上,origin 是 *,方法允许 GET、POST、OPTIONS。路由是 GET /fetch-content,从查询参数读 url。没有 url 时返回 400 和 URL parameter is required。取到内容就 { success: true, content }。抛错时路由自己把状态写成 500。错误处理是另一个中间件,写在 router.routes() 之前没有发生,它排在路由注册之后。Koa 里先注册的才包住后面的。排在路由后面的错误处理看不到路由里已经抛出的异常。路由内部的 try 已经把异常变成 500 响应,那个后挂的中间件更不会再跑到。
启动参数多了 --no-sandbox 和 --disable-setuid-sandbox。导航超时 setDefaultNavigationTimeout(30000),goto 的 timeout 也是 30000。选择器不存在时 $eval 抛错,信息被包成 Failed to fetch content: 再加原来的消息。浏览器在 finally 里关闭。若 launch 本身失败,还没进入 try 的 finally 就不属于这次启动失败。launch 失败会直接进路由的 catch。

可执行路径只适用于那一台苹果电脑。换到别的系统,这个路径不存在,launch 失败,接口 500。回答没有从环境变量读路径。无头和沙箱参数也不改变路径是否存在。
查询参数里的地址不该原样打开
接口把查询字符串里的 url 交给浏览器。跨域又是星号。任意网页都可以让这台机器去打开调用方给的地址。这不是只读自己已经打开的页面。原示例里的那一个地址被换成了由调用方传入。选择器仍固定是 #page-content。页面上没有这个 id 时,不会返回空字符串,而是抛错。超时是 30 秒,networkidle0 要等网络安静,慢页面会先撞上超时。
监听端口是环境变量 PORT,否则 3000。日志是 Server running on port。没有鉴权。400 只检查 url 是否缺失,不检查是不是允许的主机。

错误处理要注册在路由之前,才能包住后面的异常。浏览器路径不要写死在某一个系统的应用目录里。不要用星号跨域去打开调用方随意传入的地址。选择器缺失应是明确的失败,而不是把带签名的示例地址留在代码里。



