解决Halo博客使用链接卡片无法加载图片

Tch
Tch
发布于 2026-01-03 / 7 阅读
0
0

1. 发现问题QQ超级表情_qlottie-73

最近在写年终总结的时候发现文章链接使用链接卡片时,文章的封面图不能加载,显示效果如下。

A0CD886C-1644-4423-BB39-7E745269CC05.png

但是你看,图片明明是可以加载的,问题出在哪里?

34F467AC-2F8A-4EB0-8F20-0009B1A8C14C.png

2. 分析问题QQ超级表情_qlottie-10

图片是可以加载的,下面的<hyperlink-card>标签就是链接卡片,框出来的部分就是本该显示出来的图片。

很显然,问题出在referrerpolicy="no-referrer"上了。

DB772A49-CA9A-450F-97BA-541A3512022D.png

referrerpolicy用于控制浏览器发送http请求时如何携带Referer信息的,"no-referrer"就表示完全禁止发送Referer头部。当链接卡片加载图片时,浏览器不会将当前页面的地址告诉目标服务器,对于本站来讲就是腾讯云对象存储COS

腾讯云对象存储COS防盗链设置中,我是设置了拒绝空Referer的。

如果允许空Referer的话,referrerpolicy="no-referrer"肯定能加载图片,但这就不安全了。

3. 解决问题QQ超级表情_qlottie-28

懒得去分析链接卡片为什么是no-referrer的,只要把referrerpolicy="no-referrer"改成referrerpolicy="strict-origin-when-cross-origin"不就解决问题了嘛,在跨域请求时只发送源作为Referer

先试验一下,获取class="usp-n3v8cb"img元素,获取到的是一个空的NodeList。为什么呢?

<hyperlink-card>标签是链接卡片,我注意到在它的下面有个#shadow-root (open),这是个什么?

在Web开发中,#shadow-root (open)是Shadow DOM的根节点。Shadow DOM是一种封装技术,允许将DOM树附加到常规DOM树中的某个元素上,但保持其内部结构的私有性,从而实现样式和行为的封装。

  1. Shadow DOM:它是Web组件标准的一部分,用于创建封装的“影子”DOM树,该树附加到常规DOM元素(称为影子宿主)上,但与其子代分开渲染。这意味着Shadow DOM内部的样式和脚本不会影响到外部DOM,外部的样式也不会影响到Shadow DOM内部(除了某些特定的CSS属性,如继承属性)。

  2. #shadow-root:当为一个元素创建Shadow DOM时,该元素下会附加一个shadow root,即影子根。它是Shadow DOM树的根节点。

  3. open:表示这个Shadow DOM是开放的,可以通过JavaScript访问。例如,通过element.shadowRoot可以获取到该影子根并操作其内部节点。

  4. closed:与之相对的是closed模式,即影子根对外部是关闭的,element.shadowRoot会返回null,因此外部无法直接访问Shadow DOM内部。

以上是来自Deepseek的介绍,可以看出这种Shadow DOM不会影响到外部DOM,也不受外部影响,所以上文的document.querySelectorAll('img.usp-n3v8cb')是无法获取到<img>元素的。

但是对于开放的Shadow DOM,是可以通过element.shadowRoot获取的,来试一下。

可以看出,这个思路是可行的,referrerpolicy的值被变更成strict-origin-when-cross-origin

代码如下,只需要把如下代码用forEach循环实现就行了。

document
	.querySelectorAll('hyperlink-card')[0]
	.shadowRoot
	.querySelectorAll('img.usp-n3v8cb[referrerpolicy="no-referrer"]')[0]
	.setAttribute('referrerpolicy', 'strict-origin-when-cross-origin')

完整的js代码如下,使用forEach替换每一个hyperlink-card下的img

考虑到Shadow DOM的渲染需要额外时间,即使在DOMContentLoaded事件触发后,Shadow DOM内部的元素也可能尚未完全渲染完成,所以加了一个500ms的延迟。500ms是一个相对安全的等待时间,足够覆盖大多数浏览器的渲染周期,既不会影响用户体验,又能确保Shadow DOM已渲染完成,实际体验下来也是确实可行的。

// 解决链接卡片图片加载时不发送Referer头
document.addEventListener('DOMContentLoaded', function() {
    setTimeout(() => {
        const hyperlinks = document.querySelectorAll('hyperlink-card');
        
        hyperlinks.forEach(link => {
            if (!link.shadowRoot || link.shadowRoot.mode !== 'open') return;
            
            const imgs = link.shadowRoot.querySelectorAll('img.usp-n3v8cb[referrerpolicy="no-referrer"]');
            
            imgs.forEach(img => {
                img.setAttribute('referrerpolicy', 'strict-origin-when-cross-origin');
            });
        });
    }, 500);
});

看看最终效果。

以上。


评论