四组对 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 不会触发重新加载和执行
必须
- 插入新标签;
- 克隆并替换旧标签;
才能触发脚本加载和执行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组代码
以下的代码:
- 判断 no.js不够精准,可能误判 no.jsp 或 ?debug=no.js
- el.tagName === “IMG”可以转小写以兼容库或 XHTML
- 事件是
DOMContentLoaded时,可能 iframe 还没加载完全,可能导致 iframe 内容不能被加上时间戳 - 即使 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);
}
});
});