使用Cypress测试站点地图链接时遇429拒绝服务错误,如何解决?
解决Cypress批量请求站点地图URL触发429限流的方案
1. 串行请求并添加间隔时间
直接并行遍历所有URL会瞬间发起大量请求,触发反爬机制。改成串行逐个请求,每个请求后添加等待时间,模拟正常用户的浏览节奏。
let results = []; cy.request('sitemap.xml') .then(response => { return Cypress.$(response.body).find('loc') .toArray().map(el => el.innerText) }) .then(urls => { // 递归串行处理每个URL const processNextUrl = (index) => { if (index >= urls.length) return; const currentUrl = urls[index]; cy.request({ url: currentUrl, failOnStatusCode: false, // 模拟真实浏览器请求头,避免被识别为爬虫 headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36', 'Referer': new URL(currentUrl).origin // 添加上游域名作为Referer } }) .then(response => { results.push({ url: currentUrl, status: response.status }); }) .wait(1000) // 每个请求间隔1秒,可根据网站限流规则调整 .then(() => processNextUrl(index + 1)); }; processNextUrl(0); })
2. 分批次请求+批次间隔
如果串行速度太慢,可以将URL分成小批次,每批次并行请求,批次之间添加较长等待时间,平衡效率和限流风险。
let results = []; cy.request('sitemap.xml') .then(response => { return Cypress.$(response.body).find('loc') .toArray().map(el => el.innerText) }) .then(urls => { const batchSize = 10; // 每批次处理10个URL const urlBatches = []; // 将URL数组分割为多个批次 for (let i = 0; i < urls.length; i += batchSize) { urlBatches.push(urls.slice(i, i + batchSize)); } // 递归处理每个批次 const processNextBatch = (batchIndex) => { if (batchIndex >= urlBatches.length) return; const currentBatch = urlBatches[batchIndex]; // 并行处理当前批次的所有请求 Cypress.Promise.all( currentBatch.map(url => cy.request({ url, failOnStatusCode: false, headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36' } }).then(res => results.push({ url, status: res.status })) ) ) .wait(5000) // 批次之间间隔5秒,可按需调整 .then(() => processNextBatch(batchIndex + 1)); }; processNextBatch(0); })
3. 用Node.js任务(Node Task)控制并发
Cypress的命令队列在浏览器环境运行,限流控制不够灵活。可以借助Node.js任务,用专业的限流库(如p-limit)精准控制并发数,同时避开浏览器的请求限制。
步骤1:安装依赖
npm install p-limit --save-dev
步骤2:配置Cypress任务(cypress.config.js)
const { defineConfig } = require('cypress'); const pLimit = require('p-limit'); module.exports = defineConfig({ e2e: { setupNodeEvents(on, config) { on('task', { async checkSitemapUrls({ urls }) { const limit = pLimit(5); // 限制同时发起5个请求 const results = await Promise.all( urls.map(url => limit(async () => { try { const response = await fetch(url, { headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36' } }); return { url, status: response.status }; } catch (error) { return { url, status: 'error', message: error.message }; } })) ); return results; } }); }, }, });
步骤3:在测试代码中调用任务
cy.request('sitemap.xml') .then(response => { return Cypress.$(response.body).find('loc') .toArray().map(el => el.innerText) }) .then(urls => { cy.task('checkSitemapUrls', { urls }).then(results => { // 处理最终结果,比如打印或断言 console.log('站点地图URL检测结果:', results); }); })
额外注意事项
- 调整间隔/并发数:根据目标网站的限流规则灵活调整,比如有些网站可能需要2秒以上的间隔,或者更低的并发数。
- 检查robots.txt:确认目标网站允许爬取站点地图中的URL,避免违反爬虫协议。
- 白名单权限:如果测试的是自家网站,可以联系运维团队将测试IP加入限流白名单,从根源解决问题。
内容的提问来源于stack exchange,提问作者user20008783
相关产品推荐
相关产品推荐

