You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何设置超时函数防止Heroku返回H13错误代码

问题根因

你之前判断的「请求超时导致H13」是完全错误的,直接看崩溃日志的核心报错即可定位根因:

Error: Failed to launch the browser process!
chrome: error while loading shared libraries: libnss3.so: cannot open shared object file: No such file or directory

opensea-scraper 底层依赖Puppeteer(无头浏览器)实现爬取逻辑,Puppeteer自带的Chromium运行需要多个系统底层动态链接库,Heroku默认的Node.js运行环境是裁剪过的轻量镜像,没有预装这些依赖,所以接口调用触发Puppeteer启动浏览器时,进程直接因缺库崩溃,没有返回任何响应才触发H13错误。整个崩溃过程实际只用了2.5秒(日志里标记service=2510ms),和30秒超时规则没有任何关系,你看到的10秒左右崩溃是本地计时误差,你提到的「每3秒轮询保活」的方案是解决真实请求超时的,对当前缺库崩溃的问题完全无效。

另外你现有代码还存在异步逻辑bug:forEach 不会等待内部async函数执行,会直接提前返回响应,导致返回的数据不完整,这个bug不会触发崩溃,但会导致接口返回结果异常。

修复方案

按以下步骤操作即可解决问题:

  • 安装Puppeteer运行所需系统依赖
    进入Heroku应用后台的构建包(Buildpacks)配置页,添加Puppeteer官方适配的Heroku构建包,将其排序在Node.js默认构建包之前,重新部署应用时构建包会自动安装所有Chromium运行需要的系统库,无需手动逐个安装依赖。
  • 配置Puppeteer启动参数适配Heroku环境
    Heroku环境的权限限制不允许Chromium默认的沙箱启动模式,调用OpenseaScraper.rankings()时需要传入适配的启动参数,否则即使装完依赖也会启动失败:
    const ranking = await OpenseaScraper.rankings({
      puppeteer: {
        args: [
          '--no-sandbox',
          '--disable-setuid-sandbox',
          '--disable-dev-shm-usage'
        ]
      }
    })
    
  • 修复接口异步逻辑bug
    把原来的forEach遍历改成for...of循环,避免异步逻辑未执行完就提前返回响应。数据库存库逻辑不需要阻塞接口返回,可以放在后台异步执行,接口拿到爬取结果后直接返回即可,修复后的接口代码参考:
    router.get('/', async (req, res) => {
      try {
        const ranking = await OpenseaScraper.rankings({
          puppeteer: {
            args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage']
          }
        })
        const NFTs = []
        for (const item of ranking) {
          const floorPrice = item.floorPrice?.amount || 0
          const nftItem = {
            slug: item.slug,
            name: item.name,
            logoUrl: item.logo,
            floorPrice
          }
          NFTs.push(nftItem)
          // 查库存库逻辑异步执行,不阻塞接口返回
          NFT.findOne({ slug: item.slug }, (err, existRecord) => {
            if (err) return console.error('查库失败:', err)
            if (!existRecord) new NFT(nftItem).save().catch(e => console.error('存库失败:', e))
          })
        }
        res.json(NFTs)
      } catch(err) {
        console.error('接口运行报错:', err)
        res.status(500).json({ msg: '服务内部错误' })
      }
    })
    
  • 可选优化
    OpenSea排名数据更新频率很低,不需要每次接口请求都实时启动浏览器爬取,可以加个定时任务,每10~15分钟爬一次数据写入MongoDB,接口请求直接读库返回,响应速度可以降到几十毫秒,也能避免Puppeteer偶发启动失败导致接口不可用。

内容的提问来源于stack exchange,提问作者Daniel Brannon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 19:01:08