两组对 web 网页的JS,IMG的SRC进行遍历并增加时间戳的JS代码


四组对 web 网页的JS,IMG的SRC进行遍历并增加时间戳的JS代码,并对引用的 iframe 的JS,IMG的SRC进行遍历

建议使用第1组代码(其他组别的代码没有过滤base64的图片,导致base64图片不能显示)

第1组代码



document.addEventListener("DOMContentLoaded", function () {
    const timestamp = Date.now();
    const baseURL = window.location.origin;

    // 处理脚本更新
    document.querySelectorAll('script[src]:not([src*="?v="])').forEach(oldScript => {
        try {
            const scriptUrl = new URL(oldScript.src, baseURL);
            if (!scriptUrl.pathname.endsWith("no.js")) return;

            const newScript = document.createElement("script");
            for (const { name, value } of oldScript.attributes) {
                newScript.setAttribute(name, value);
            }
            scriptUrl.searchParams.set("v", timestamp);
            newScript.src = scriptUrl.href;

            newScript.onerror = () => {
                console.error("脚本加载失败:", scriptUrl.href);
                document.head.appendChild(oldScript.cloneNode(true));
            };
            oldScript.parentNode.replaceChild(newScript, oldScript);
        } catch (e) {
            console.warn("脚本替换失败:", e);
        }
    });

    // 处理图片更新
    const processElements = (elements, baseURL) => {
        elements.forEach(el => {
            try {
                if (el.tagName.toLowerCase() === 'img' && el.src) {
                    const urlObj = new URL(el.src, baseURL);
                    urlObj.searchParams.set("v", timestamp);
                    el.src = urlObj.href;
                }
            } catch (e) {
                console.warn("URL 解析失败:", e);
            }
        });
    };

    processElements([...document.querySelectorAll("img[src]")].filter(img => !img.src.startsWith("data:image/")), baseURL);

    // 处理 iframe 内部的图片更新
    document.querySelectorAll("iframe").forEach(iframe => {
        const processIframe = () => {
            try {
                const doc = iframe.contentDocument;
                if (!doc) return;
                processElements([...doc.querySelectorAll("img[src]")].filter(img => !img.src.startsWith("data:image/")), iframe.contentWindow.location.href);
            } catch (e) {
                console.warn("跨域 iframe 访问失败:", iframe.src);
            }
        };

        const waitForDocumentReady = (doc, callback) => {
            let timeoutId;
            const checkReady = () => {
                if (doc.readyState === 'complete') {
                    clearTimeout(timeoutId);
                    callback();
                } else {
                    requestAnimationFrame(checkReady);
                }
            };
            timeoutId = setTimeout(() => {
                console.warn("iframe 加载超时", doc);
                callback();
            }, 30_000);
            checkReady();
        };

        const onLoad = () => {
            if (iframe.contentDocument) {
                waitForDocumentReady(iframe.contentDocument, processIframe);
            }
        };

        iframe.addEventListener('load', onLoad);
        if (iframe.contentDocument && ['interactive', 'complete'].includes(iframe.contentDocument.readyState)) {
            processIframe();
        }
    });
});

第2组代码

上一组代码只能动态更新IMG,而JS即使更新了SRC,还是不会重载。
所以另写一组代码,对JS进行更新。

由于JS文件在单纯修改 <script>src 不会触发重新加载和执行
必须

  1. 插入新标签;
  2. 克隆并替换旧标签;
    才能触发脚本加载和执行
    document.addEventListener("DOMContentLoaded", function () {
        // 由于对 <script> 修改 src 并添加时间戳,一般不会重新执行脚本
        // 所以使用下列代码破坏缓存策略,强制更新 no.js
        
        // 获取所有脚本标签(排除已包含版本号的)
        document.querySelectorAll('script[src]:not([src*="?v="])').forEach(oldScript => {
            try {
                // 解析脚本的完整 URL
                const scriptUrl = new URL(oldScript.src, window.location.origin);
    
                // 检查 pathname 是否以 no.js 结尾
                if (!scriptUrl.pathname.endsWith("no.js")) return;
    
                // 创建新脚本标签
                const newScript = document.createElement("script");
    
                // 克隆所有原属性(保留 async/defer/integrity 等)
                for (const { name, value } of oldScript.attributes) {
                    newScript.setAttribute(name, value);
                }
    
                // 添加时间戳参数
                scriptUrl.searchParams.set("v", Date.now());
                newScript.src = scriptUrl.href;
    
                // 处理加载失败
                newScript.onerror = () => {
                    console.error("脚本加载失败:", url.href);
                    // 可选回退逻辑:重新插入旧脚本
                    document.head.appendChild(oldScript.cloneNode(true));
                };
                // 替换旧标签
                oldScript.parentNode.replaceChild(newScript, oldScript);
    
            } catch (e) {
                console.warn('脚本替换失败:', e);
            }
        });
    });

第3组代码

以下的代码:

  1. 判断 no.js不够精准,可能误判 no.jsp 或 ?debug=no.js
  2. el.tagName === “IMG”可以转小写以兼容库或 XHTML
  3. 事件是 DOMContentLoaded 时,可能 iframe 还没加载完全,可能导致 iframe 内容不能被加上时间戳
  4. 即使 iframe 里的 HTML 文档已经 存在,但可能 iframe.onload 触发得 太早,导致 iframe.contentDocument 还没完全初始化,所以 doc 仍然是 null
    本代码在本地测试不能通过,(跑完 let doc = iframe.contentDocument || iframe.contentWindow.document 之后停止)可能因为本地响应事件很短,在远程服务器通过,可能是远程服务器响应时间较长
document.addEventListener("DOMContentLoaded", function () {
    const timestamp = Date.now();

    // 处理 index.html 本身的 JS 和图片
    document.querySelectorAll("img[src], script[src]").forEach((el) => {
        if (el.src.includes("no.js") || el.tagName === "IMG") { // 只修改特定JS & 所有图片
            let url = new URL(el.src, window.location.origin);
            url.searchParams.set("v", timestamp);
            el.src = url.href;
        }
    });

    // 遍历所有 iframe,给 iframe 里的 JS 和图片加时间戳
    document.querySelectorAll("iframe").forEach((iframe) => {
        try {
            let doc = iframe.contentDocument || iframe.contentWindow.document;
            if (!doc) throw new Error("无法访问 iframe 文档");

            doc.querySelectorAll("img[src], script[src]").forEach((el) => {
                if (el.src.includes("no.js") || el.tagName === "IMG") { // 只修改特定JS & 所有图片
                    let url = new URL(el.src, window.location.origin);
                    url.searchParams.set("v", timestamp);
                    el.src = url.href;
                }
            });
        } catch (e) {
            console.warn("无法访问 iframe 内容,可能是跨域问题:", iframe.src);
        }
    });
});

文章作者: Alan Work
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Alan Work !
  目录