之前写 blog
,一直是用的 gitee
的图床。原因是不想自己去购买 CDN
服务器,同时也想减少自己服务器的压力。突然有一天,网站中使用 gitee
的图片崩溃了,返回我们一个 gitee
的小 logo
图片。奇怪的是,单独访问这个图片 url
,又能正常访问。起初以为是服务器异常,过两天自动就好了,但是过了好几天,仍然是这样,感觉事情不太对劲。然后查了一下,果然,很多人也遇见了这个问题。
为什么会这样?
由于许多人发现了国内使用 gitee
图床访问速度快,使用起来也方便,所以都在自己的项目中,使用 gitee
图床作为自己的 CDN
服务器。少一点人使用没啥问题,忍了。但是大家开始滥用它,gitee
也遭不住啊。所以加入了 防盗链
功能。
什么是防盗链?
简单理解就是防止 OSS
资源被别人盗用。目前 阿里云
和 腾讯云
都支持配置 黑名单
和 白名单
来开启使用。
实现原理?
HTTP
协议规范定义了在请求中加入 Referrer
字段,用于表示请求来源。该字段由浏览器在发起 HTTP
请求时指定。比如我们访问一篇文章,这篇文章中有一些图片,查看 Request Headers
:

可以看到这个里面有 Referrer
,它表示这个图片是从哪个网站的哪个页面请求的。
所以通过对 HTTP
请求头中的 Referrer
判断可以知道这条请求是正常访问的还是来自其他网站。
如何绕过?
前面简单说了一下 什么是防盗链
以及它的 实现原理
。那对于上面提到的那种,在网站中不能使用,但是直接访问 url
又可以使用的这种方式我们可以怎么绕过并继续使用它吗?
查看 https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Referrer-Policy 可以发现 Referrer
有下面几类值:
-
no-referrer
:整个 Referer 首部会被移除。访问来源信息不随着请求一起发送。 -
no-referrer-when-downgrade
(默认值):在没有指定任何策略的情况下用户代理的默认行为。在同等安全级别的情况下,引用页面的地址会被发送 (HTTPS->HTTPS),但是在降级的情况下不会被发送 (HTTPS->HTTP)。 -
origin
:在任何情况下,仅发送文件的源作为引用地址。 -
origin-when-cross-origin
:对于同源的请求,会发送完整的 URL 作为引用地址,但是对于非同源请求仅发送文件的源。 -
same-origin
:对于同源的请求会发送引用地址,但是对于非同源请求则不发送引用地址信息。 -
strict-origin
:在同等安全级别的情况下,发送文件的源作为引用地址 (HTTPS->HTTPS),但是在降级的情况下不会发送 (HTTPS->HTTP)。 -
strict-origin-when-cross-origin
:对于同源的请求,会发送完整的 URL 作为引用地址;在同等安全级别的情况下,发送文件的源作为引用地址 (HTTPS->HTTPS);在降级的情况下不发送此首部 (HTTPS->HTTP)。 -
unsafe-url
:无论是同源请求还是非同源请求,都发送完整的 URL(移除参数信息之后)作为引用地址。
我们只要将 Referrer
的值设置成 no-referrer
或者 same-origin
就可以了。
那具体怎么做呢?
方法一
设置 meta
标签的 content
值。
<meta name="referrer" content="no-referrer" />
这样设置后,图片果然能够正常访问了。
但是:这样设置后,发现 百度统计
无效了。原因是百度统计也需要根据 referrer
值来判断用户是从哪里进入的,访问了哪些页面。
怎么办?
方法二
设置图片的 referrerpolicy。
<img src="https://....jpg" alt="图片" referrerpolicy="no-referrer" />
不错,单个图片可以这样设置。但是对于一些文章中使用了图片呢?
如果文章的内容是 富文本
。那在渲染前,我们可以通过正则 str.replace(/<img/g, '<img referrerpolicy="no-referrer"')
等代码方式先将 富文本
中的 <img ... />
中先添加一下 referrerpolicy="no-referrer"
属性后再渲染。
如果文章的内容是 “一颗树”
。在代码中通过第三方库来渲染的,或者其它不方便在渲染前拿到文章内容的情况,比如 nuxt-content
,这时我们应该怎么办呢?方法也简单,查询出所有的 img
标签,给它们加上 referrerpolicy="no-referrer"
属性。
const imgs = document.querySelectorAll('img');
imgs.forEach(img => {
img.setAttribute('referrerpolicy', 'no-referrer');
img.setAttribute('src', `${img.src}`);
})
这样写后,页面中访问的还是裂开的图片,因为图片没有再请求,怎么办?
给图片的 url
加上一个随机参数,利用浏览器的特性,图片 url
发生改变,就会重新请求图片资源的方式。
const imgs = document.querySelectorAll('img');
imgs.forEach(img => {
img.setAttribute('referrerpolicy', 'no-referrer');
img.setAttribute('src', `${img.src}?imgRandom=${Date.now()}`);
})
但这存在一个问题,url
每次都不一样,没办法触发浏览器缓存功能。每次都要请求一次,特别耗资源。
再优化:
updateImgProps() {
let imgRandom = localStorage.getItem('imgRandom');
if (!imgRandom) {
imgRandom = Date.now();
localStorage.setItem('imgRandom', imgRandom);
}
const imgs = document.querySelectorAll('img');
imgs.forEach(img => {
img.setAttribute('referrerpolicy', 'no-referrer');
img.setAttribute('src', `${img.src}?imgRandom=${imgRandom}`);
})
}
localStorage
中存一个随机生成的变量,有的话直接读取并使用,没有的话就生成一个并保存在 localStorage
中,以便下次使用。这样既改变了图片的 url
以触发浏览器重新请求 url
,同时如果之前访问过,浏览器中有缓存,浏览器会使用缓存中的图片资源,减少 HTTP
请求。
总结
通过上面的学习研究,更加了解了 Referrer
的工作方式以及它的其它值及作用。
以上方法只是为了探索解决方法,并不推荐使用。最好还是使用自己的 CDN
服务器资源,别浪费公共服务器带给大家的便利。又或者万一哪天防盗链机制变了,设置白名单才能访问,那不管怎么设置都是无用的。因此造成的一些损失,也只能自己承担。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/83074.html