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

Docker部署NestJS项目Puppeteer报Target.setAutoAttach错误求助

问题:NestJS + Puppeteer Docker部署出现Protocol error (Target.setAutoAttach): Target closed.

环境与配置

Dockerfile

###################
# BUILD FOR LOCAL DEVELOPMENT
###################

FROM --platform=linux/amd64 node:18-alpine As development

# Create app directory
WORKDIR /usr/src/app

# Copy application dependency manifests to the container image.
# A wildcard is used to ensure copying both package.json AND package-lock.json (when available).
# Copying this first prevents re-running npm install on every code change.
COPY --chown=node:node package*.json ./

# Install app dependencies using the `npm ci` command instead of `npm install`
ENV PUPPETEER_SKIP_DOWNLOAD=true
RUN npm ci

# Bundle app source
COPY --chown=node:node . .

# Use the node user from the image (instead of the root user)
USER node

###################
# BUILD FOR PRODUCTION
###################

FROM --platform=linux/amd64 node:18-alpine As build

WORKDIR /usr/src/app

COPY --chown=node:node package*.json ./

# In order to run `npm run build` we need access to the Nest CLI which is a dev dependency. In the previous development stage we ran `npm ci` which installed all dependencies, so we can copy over the node_modules directory from the development image
COPY --chown=node:node --from=development /usr/src/app/node_modules ./node_modules

COPY --chown=node:node . .

# Run the build command which creates the production bundle
RUN npm run build

# Set NODE_ENV environment variable
ENV NODE_ENV production

# Running `npm ci` removes the existing node_modules directory and passing in --only=production ensures that only the production dependencies are installed. This ensures that the node_modules directory is as optimized as possible
ENV PUPPETEER_SKIP_DOWNLOAD=true
RUN npm ci --only=production && npm cache clean --force

USER node

###################
# PRODUCTION
###################

FROM --platform=linux/amd64 node:18-alpine As production

# Copy the bundled code from the build stage to the production image
COPY --chown=node:node --from=build /usr/src/app/node_modules ./node_modules
COPY --chown=node:node --from=build /usr/src/app/dist ./dist

RUN apk add chromium

EXPOSE 3010
ENV PORT 3010

ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser

# Start the server using the production build
CMD [ "node", "dist/main.js" ]

启动错误日志

[Nest]  ERROR [ExceptionHandler] Protocol error (Target.setAutoAttach): Target closed.
 ProtocolError: Protocol error (Target.setAutoAttach): Target closed.
    at /node_modules/puppeteer-core/lib/cjs/puppeteer/common/Connection.js:104:24
    at new Promise (<anonymous>)
    at Connection.send (/node_modules/puppeteer-core/lib/cjs/puppeteer/common/Connection.js:100:16)
    at ChromeTargetManager.initialize (/node_modules/puppeteer-core/lib/cjs/puppeteer/common/ChromeTargetManager.js:247:82)
    at CDPBrowser._attach (/node_modules/puppeteer-core/lib/cjs/puppeteer/common/Browser.js:156:76)
    at CDPBrowser._create (/node_modules/puppeteer-core/lib/cjs/puppeteer/common/Browser.js:49:23)
    at ChromeLauncher.launch (/node_modules/puppeteer-core/lib/cjs/puppeteer/node/ChromeLauncher.js:130:53)
    at async InstanceWrapper.useFactory [as metatype] (/node_modules/@noahqte/nest-puppeteer/dist/puppeteer-core.module.js:38:24)
    at async Injector.instantiateClass (/node_modules/@nestjs/core/injector/injector.js:355:37)
    at async callback (/node_modules/@nestjs/core/injector/injector.js:56:34)

相关代码

Service代码

constructor(
    private appService: AppService,
    @InjectBrowser() private readonly browser: Browser,
  ) {}
async onSendForm1(data, @Ctx() ctx?: Context) {
    const page = await this.browser.newPage()
    await page.setRequestInterception(true)
    await page.once('request', (interceptedRequest) => {
      interceptedRequest.continue({ method: 'POST', postData: JSON.stringify(data), headers: { 'Content-Type': 'application/json' } })
    })
    await page.goto('http://localhost:3010', { waitUntil: 'networkidle2' })
    const fileName = Guid.newGuid().toString()
    await page.pdf({
      path: `${this.appService.pathFile}${fileName}.pdf`,
      scale: 0.9,
      format: 'A4',
      landscape: false,
      pageRanges: '1,3',
    })
    await page.close()
    await this.browser.close()
}

AppModule代码

@Module({
  imports: [
    PuppeteerModule.forRoot({ pipe: true, isGlobal: true }),
  ],
  controllers: [AppController],
  providers: [AppService],
  exports: [AppService],
})

解决方案

  • 添加容器环境下Chromium启动参数:容器中运行Chromium需要禁用沙箱等参数,修改PuppeteerModule的配置,指定必要的启动选项:
PuppeteerModule.forRoot({
  isGlobal: true,
  launch: {
    executablePath: process.env.PUPPETEER_EXECUTABLE_PATH,
    args: [
      '--no-sandbox',
      '--disable-setuid-sandbox',
      '--disable-dev-shm-usage',
      '--disable-gpu',
      '--no-zygote',
      '--single-process'
    ],
    headless: 'new' // 新版本Puppeteer推荐使用该无头模式
  }
})
  • 禁止全局Browser实例被关闭:当前代码中每次调用接口都会关闭全局注入的Browser实例,导致后续请求无法创建新页面,移除await this.browser.close():
async onSendForm1(data, @Ctx() ctx?: Context) {
    const page = await this.browser.newPage()
    try {
      await page.setRequestInterception(true)
      await page.once('request', (interceptedRequest) => {
        interceptedRequest.continue({ method: 'POST', postData: JSON.stringify(data), headers: { 'Content-Type': 'application/json' } })
      })
      await page.goto('http://localhost:3010', { waitUntil: 'networkidle2' })
      const fileName = Guid.newGuid().toString()
      await page.pdf({
        path: `${this.appService.pathFile}${fileName}.pdf`,
        scale: 0.9,
        format: 'A4',
        landscape: false,
        pageRanges: '1,3',
      })
    } finally {
      await page.close()
      // 移除此行:await this.browser.close()
    }
}
  • 确保文件目录权限正确:在Dockerfile的production阶段添加目录创建与权限配置,避免生成PDF时权限不足:
# 在production阶段,添加在RUN apk add chromium之后:
RUN mkdir -p /usr/src/app/pdf && chown -R node:node /usr/src/app/pdf
# 注意:需确保this.appService.pathFile指向该目录
  • 验证依赖版本兼容性:确认nestjs-puppeteer与puppeteer-core版本匹配,避免因版本差异导致的协议通信错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 09:02:58