Puppeteer中fetch请求Promise始终处于pending状态问题排查
Puppeteer登录后Fetch请求Promise始终Pending的解决办法
核心问题分析
page.evaluate未传递Fetch的Promise
原代码里page.evaluate内部执行了fetch,但没有返回这个异步Promise,外部的await只会等evaluate里的同步代码跑完,不会等待fetch请求完成。如果请求因参数错误、服务器无响应等原因卡住,就会一直处于pending状态。浏览器上下文变量未正确传入
this.json_data_在浏览器页面的上下文里是未定义的——page.evaluate的回调运行在浏览器环境,和Node.js上下文完全隔离,直接引用Node端变量会导致请求body为undefined,服务器可能拒绝处理,进而让请求卡住。登录导航等待的潜在问题
即使使用了Promise.all配合waitForNavigation,如果登录是AJAX异步提交而非页面跳转,waitForNavigation会超时,后续的fetch可能在未登录状态下发送,引发异常。
修正后的代码示例
const puppeteer = require('puppeteer'); (async () => { const browser = await puppeteer.launch(); const page = await browser.newPage(); try { await page.goto('https://id.adform.com/sts/login'); // 执行登录并等待页面导航完成 await Promise.all([ page.evaluate((username, password) => { const setValue = Object.getOwnPropertyDescriptor( window.HTMLInputElement.prototype, "value" ).set; const modifyInput = (name, value) => { const input = document.getElementsByName(name)[0]; setValue.call(input, value); input.dispatchEvent(new Event('input', { bubbles: true })); input.dispatchEvent(new Event('change', { bubbles: true })); // 补充change事件触发表单校验 }; modifyInput('username', username); modifyInput('password', password); document.querySelector("button").click(); }, "another", "some.123"), // 把账号密码作为参数传入,避免上下文冲突 page.waitForNavigation({ waitUntil: 'networkidle2', timeout: 30000 }), // 添加30秒超时防止无限等待 ]); // 传入请求数据,发送POST并返回结果 const json_data_ = { /* 你的请求数据 */ }; const fetchResult = await page.evaluate((jsonData) => { return fetch('https://page_after_navigation.com', { method: 'POST', headers: { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36', 'Content-Type': 'application/json', // 告知服务器请求格式 }, body: JSON.stringify(jsonData), }) .then(response => { if (!response.ok) { throw new Error(`请求失败:状态码 ${response.status}`); } return response.text(); }) .catch(error => { console.error('Fetch出错:', error); throw error; // 抛出错误让外部捕获处理 }); }, json_data_); // 将Node端的请求数据传入浏览器上下文 console.log('请求结果:', fetchResult); } catch (error) { console.error('流程出错:', error); } finally { await browser.close(); } })();
调试建议
开启可视化调试:启动浏览器时打开开发者工具,直观查看网络请求状态
const browser = await puppeteer.launch({ headless: false, devtools: true });在Network面板可以看到fetch请求的发送情况、响应状态、请求头/体是否正确。
验证登录状态:导航完成后,通过截图或页面内容确认是否登录成功
await page.screenshot({ path: 'after_login.png' }); const isLoggedIn = await page.evaluate(() => { return document.body.textContent.includes('你好,xxx'); // 替换为登录后页面的特征文本 }); console.log('是否登录成功:', isLoggedIn);
内容的提问来源于stack exchange,提问作者tesla john
相关产品推荐
相关产品推荐

