WebdriverIO检测页面死链报TypeError读取url错误求解
问题根因
报错和检测失效由4个核心问题导致:
- Node环境下的
node-fetch不会像浏览器一样自动补全相对路径的域名:你配置的baseUrl仅对browser.url()方法生效,直接把/status_codes这类相对路径传给fetch,会被解析为非法的本地文件路径,请求直接进入rejected状态。 Promise.allSettled返回结果取值错误:rejected状态的响应项,错误信息存储在reason字段,原代码中读取errorsUnless.value.url属于访问不存在的属性,直接触发TypeError。- 死链判断逻辑不全:
fetch仅在网络不通、URL非法时会reject,对于请求成功但返回4xx/5xx状态码的死链,原有逻辑完全无法识别。 - 原代码直接在
$$('a')后链式调用map的写法在部分WebdriverIO版本中存在异步遍历问题,可能漏拿链接的href属性。
修复方案
- 对抓取到的所有href做预处理:过滤掉非HTTP协议的特殊链接,将相对路径统一拼接为完整的绝对路径后再发起请求
- 修正allSettled结果的取值逻辑,通过可选链读取属性避免类型错误
- 补充HTTP状态码校验,覆盖请求成功但返回错误状态的死链场景
- 修正链接属性的异步获取写法,确保所有链接都能被正确抓取
修复后的完整代码如下:
const fetch = require('node-fetch'); describe('Broken link test', () => { it('Check the page for broken links', async () => { const brokenLinks = []; const baseUrl = browser.options.baseUrl; // 打开目标页面 await browser.url('status_codes/200'); const currentPageUrl = await browser.getUrl(); // 正确获取所有a标签的href属性 const linkElements = await $$('a'); const rawHrefs = await Promise.all( linkElements.map(link => link.getAttribute('href')) ); // 预处理链接:过滤无效链接、拼接完整路径 const validUrls = rawHrefs.reduce((list, href) => { if (!href) return list; // 跳过非HTTP协议链接 if (['javascript:', 'mailto:', 'tel:', '#'].some(prefix => href.startsWith(prefix))) { return list; } // 绝对路径直接加入 if (href.startsWith('http://') || href.startsWith('https://')) { list.push(href); return list; } // 根路径相对链接拼接baseUrl if (href.startsWith('/')) { list.push(new URL(href, baseUrl).href); return list; } // 普通相对链接拼接当前页面地址 list.push(new URL(href, currentPageUrl).href); return list; }, []); // 发起所有链接请求 const responses = await Promise.allSettled( validUrls.map(url => fetch(url, { method: 'HEAD' })) // 用HEAD请求减少带宽消耗 ); // 遍历识别死链 responses.forEach((res, idx) => { const targetUrl = validUrls[idx]; // 请求直接失败的情况 if (res.status === 'rejected') { brokenLinks.push({ url: targetUrl, reason: res.reason?.message || 'request failed' }); return; } // 请求成功但状态码异常的情况 if (!res.value.ok) { brokenLinks.push({ url: targetUrl, reason: `abnormal status code: ${res.value.status}` }); } }); // 输出结果 console.log('Total detected links:', validUrls.length); console.log('Broken links count:', brokenLinks.length); brokenLinks.forEach(link => { console.log(`Broken link: ${link.url}, reason: ${link.reason}`); }); // 可选:如果存在死链则用例失败 // expect(brokenLinks.length).toBe(0); }) })
优化点说明:检测链接时使用HEAD方法替代默认GET,仅获取响应头不需要下载响应体,能大幅提升检测速度。
内容的提问来源于stack exchange,提问作者Serhii
相关产品推荐
相关产品推荐

