未防盗链图片可通过跨域且无referrerpolicy、未标记data-secured、能正常加载三者组合识别:先用queryselectorall筛选跨域img,再filter排除同域/data url/显式禁referer,最后验证naturalwidth>0或onload事件。

要从多图文混合排版的页面中,用 matches 筛选出所有未做防盗链处理的 <img> 元素,关键不是直接靠 CSS 选择器判断“是否防盗链”,而是通过分析图片请求行为的常见特征来间接识别——因为“防盗链”本身是服务端策略,前端无法直接读取响应头,但可依据 Referer 行为、资源加载失败状态或常见防盗链响应特征进行推测。
识别未防盗链图片的核心逻辑
真正有效的判断方式是结合以下几点:
- 图片能正常加载且无跨域报错:说明服务端未校验 Referer 或放行了当前站点;
-
图片 src 域名与当前页面域名不同,但未设置
referrerpolicy="no-referrer":此时浏览器默认携带 Referer,若仍能加载,大概率未设防盗链; -
手动发起 HEAD 请求探测(需后端代理或 CORS 配合):检查响应头是否含
X-Frame-Options、Access-Control-Allow-Origin或返回 403/404;但这不属于纯前端matches范畴。
用 :not() + 属性选择器模拟“疑似未防盗链”筛选
虽然 matches() 本身不支持运行时加载检测,但你可以先用 CSS 选择器预筛出高概率未防盗链的 img,再结合 JS 验证。例如:
const suspiciousImgs = Array.from(document.querySelectorAll('img'))
.filter(img => {
const src = img.src;
const host = new URL(src).host;
const pageHost = location.host;
// 排除同域图、data URL、空 src
if (host === pageHost || src.startsWith('data:') || !src.trim()) return false;
// 检查是否显式禁用 referer(这类图即使跨域也可能被放行,但非典型“未防盗链”)
if (img.referrerPolicy === 'no-referrer') return false;
// 关键:尝试用 matches 判断是否已被标记为“已加防盗链防护”
// 比如团队约定给加了 referer 控制或代理中转的 img 加 class="safe-img"
return !img.matches('.safe-img, [data-proxy], [data-cdn="true"]');
});
借助 loading 状态和 onerror 辅助判断
更实用的方式是监听加载结果:
- 给每个跨域
<img>绑定onload和onerror; - 成功加载 → 极大概率未设防盗链;
- 触发
onerror且控制台出现 “blocked by CORS policy” 或 “Failed to load resource” → 很可能启用了 Referer 校验; - 注意:部分防盗链返回 200 + 占位图(如 1x1 gif),需额外比对尺寸或 content-length(需 fetch 配合)。
实际建议:别只依赖 matches,组合验证更可靠
单纯用 Element.matches() 无法准确判断防盗链状态,它只能匹配静态属性或类名。推荐做法是:
- 在构建阶段,由 CMS 或构建工具为经过防盗链处理(如走代理、加签名参数、改 referer)的图片自动添加
data-secured="true"; - 前端用
document.querySelectorAll('img:not([data-secured="true"])')快速获取待检查列表; - 对这些图片做轻量级探测(如定时器延时 500ms 后检查
img.naturalWidth > 0); - 将确认失败的图片记录并上报,用于后续运营或配置优化。
不复杂但容易忽略:防盗链是否生效,最终取决于服务端配置和浏览器实际发出的请求头,前端能做的只是合理推测和辅助归因。










