背景&问题

我们的网站每天都会安排进行功能检查,对于关键性的页面,还会进行全页面的链接可用性扫描。之前一直用的是 Google 浏览器上Check My Links这个扩展插件,总体来说速度还是很快的。
但是随着我们网站的安全升级,对于它高频触发的请求,我们会进行拦截重定向到锁定页面。然而由于是重定向,它识别不出来这个链接是否有问题,会被当成正常可用。
因此检测结果已经不能作为我们的测试依据,有必要对它进行改造。

解决方案

尝试直接改造Check My Links插件(失败方案)

实际业务中,我们服务端实际上是约定过特定 ip+ 请求 UA 的白名单机制,而且这个插件项目是开源的,于是一开始便打算对这个插件进行适应的改造。
然而分析了它源码、进行改造调试后发现,它的核心方法里,实际上是忽略了XMLHTTPRequest请求出错的情况。而且谷歌浏览器上的遵循的 W3C 要求,请求 UA 不让修改的。

改造为 Firefox 插件(应用方案)

Check My Links里面用了很多 chrome 特有的 Api,所以这一步我并没有直接把它迁移到 Firefox,而是二次改造 Firefox 上的Simple Link Checker这个插件,并结合我们自身的需求进行了更为深度的功能定制。

新功能点

核心源码

定制化请求头参数:

迁移到 firefox 也是因为这个关键性的参数setRequestHeader在 chrome 不被允许修改请求 UA,而 firefox 的协议是可以的。

var XMLHttpTimeout, client = new XMLHttpRequest();
client.open('GET', url, true);
const brower_UA = navigator.userAgent;
const custom_UA = `${brower_UA} Test-Header-XXX`
client.setRequestHeader("user-agent", custom_UA);
client.send();
获取当前页面所有的链接:
var links = document.getElementsByTagName("a");
封装异步检测方法,并在 for 循环里同步处理:
function sendMessagePromise(url) {
    return new Promise((resolve, reject) => {
        chrome.runtime.sendMessage({
            "action": "check",
            "url": url,
        }, function(response) {
            resolve(response);
        });
    });
}

async function linkCheck() {
    for (let i=0; i<filterLinks.length; i++){
        const ele = filterLinks[i]
        const url = ele.href;
        await sendMessagePromise(url)
          .then(response => {
              doSomething(response)        
          }
    }
}
失败重试机制

在原来的 chrome 插件里,对于请求失败的访问,默认 statusCode 为 0,虽然这是比较小概率的出现的,但是这样强制改写结果为通过,肯定是不合理的。
因此我这里是增加了对XMLHttpRequest.onError的异常捕获,并封装了可参数化调用的重试方法,默认 5 次还不成功会抛出错误。

function check(url, retryCount = 5) {
    var XMLHttpTimeout, client = new XMLHttpRequest();
    ...
    client.onerror = function(e) {
        if (retryCount <= 0) {
            resolve({
                status: 400,
                message: url,
            });
        }else {
            check(url, --retryCount)
        }
    };
}
高亮显示报错元素

对于报错的元素位置,之前工具只会是以红色背景色展示,对于我们整体主色调本身就是红色的网站来说,很不友好,有时还找不到。
因此本次我们对于报错的位置,结合 CSS 动画,进行了闪动处理,帮助检测人员快速定位到异常发生的位置。

@keyframes fade {
    from {
        opacity:1.0;
    }
    50% {
        opacity:0.4;
    }
    to {
        opacity:1.0;
    }
    }@-webkit-keyframes fade {
        from {
        opacity:1.0;
    }
    50% {
        opacity:0.4;
    }
    to {
        opacity:1.0;
    }
}

.Fail {
    border-radius:2px;
    border-color:#c0392b;
    color:#fff!important;
    background-color:#c0392b!important;
    animation:fade 600ms infinite;
    -webkit-animation:fade 600ms infinite;
}

结语

这个定制化插件,现阶段仅作为之前 chrome 的插件的替代升级工具。但长远的看,我们还可以结合业务做更多的扩展功能,看后期的使用发展和需求吧。


↙↙↙阅读原文可查看相关链接,并与作者交流