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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 15:09:17