返回博客
技术科普

图片贴到别站就变破图?403 与防盗链完整排错树(2026 更新)

发布于17 min read
分享文章

你把一张图的链接贴到博客,本机预览好好的。发布出去,别人看到的却是一个破掉的图标框。或者更糟——整张图的位置变成一片空白,什么都没有。

这个坑我踩过不止一次。线上翻过一次车是帮朋友的论坛搬图,本地全绿,上线后首页三分之一的缩略图全破,当时我还以为是缓存没清。debug 了三天才发现,根本不是我的问题——是图片来源站开了防盗链(hotlink protection),只要不是从它自己的域名发出的请求,一律挡掉。

从架构角度看,「图片在别站显示不出来」其实是三种完全不同的失败被混在一起讲。要修对,第一步是先分清楚你遇到的是哪一种。

先分清楚:403、破图、200 空白是三件事

很多人一看到图不见就统称「破图」,然后乱试一通。说穿了,这三种症状的根因差很远,对应的排错路径也不一样。

症状 HTTP 状态码 最可能的根因 排错方向
破图标框(图标裂开) 403 / 404 防盗链挡掉、或链接本身就错 查 Referer 与网址正确性
破图标框(图标裂开) 200 但非图片 拿到的是 HTML 错误页不是图片 查 Content-Type
一片空白(无裂图标) 200 CSS 盖住、或 CSP 挡加载 查 DevTools Console 与 CSP
图标转圈后消失 超时 / CORS 跨域策略或服务器超时 查 Network 的 request 细节

先看状态码,再看 Content-Type,最后才看画面。这顺序反过来就会鬼打墙。

底层原理:Referer 与防盗链怎么运作

要理解为什么别站的图会被挡,得先知道浏览器在加载图片时偷偷做了什么。

当网页 A 用 <img src="https://B.com/photo.jpg"> 去加载 B 站的图,浏览器发出的请求会夹带一个 Referer 头(对,这个词历史上就拼错了,少一个 r,将错就错到今天)。这个头告诉 B 站:「这张图是被 A 站的页面请求的。」

底层逻辑是这样:B 站的服务器或 CDN 收到请求后,会拿 Referer 的域名去比对一份白名单。比对逻辑大致是——

1. Referer 是空的(直接开图、书签)→ 看配置决定放行或挡
2. Referer 的域名在白名单 → 放行
3. Referer 的域名不在白名单 → 回 403 Forbidden

这就是防盗链。它的目的很单纯:不想让别人白嫖自己的带宽。你在自己站上嵌了 B 站的图,每次别人浏览你的页面,流量账都算在 B 站头上,B 站当然不爽。

这里有个细节很多人不知道:现代浏览器默认的 Referrer-Policy 是 strict-origin-when-cross-origin。跨域请求时,它只发出「来源域名」(例如 https://a.com/),不会发完整路径。所以防盗链拿得到你的域名,足够拿来比对白名单、也足够挡你。这就是为什么防盗链治得了 hotlink。

为什么你的图在别站变破图:一棵排错树

把上面的原理摊开,破图的根因其实可以收敛成一棵树。你照着往下走就好。

分支一:状态码是 403 吗?

是的话,九成是防盗链。B 站看到你的 Referer 不在它的白名单,直接拒绝。这种情况你改不了 B 站的配置,唯一的解是别再 hotlink 它的图(后面讲正解)。

分支二:状态码是 200,但画面破图?

打开这张「图」的原始内容看看。很可能你拿到的是一页 HTML——某些站不回 403,而是回一个「请勿盗链」的提示页,状态码还是 200。浏览器把 HTML 当图片解析,当然裂给你看。查 Content-Type 就露馅了:正常图片是 image/jpeg、image/png,错误页会是 text/html。

分支三:你贴的是「页面链接」不是「图片直链」?

这是新手最常见的坑。https://imgur.com/aBcDeFg 是一个页面,https://i.imgur.com/aBcDeFg.jpg 才是图片文件本身。前者你用 <img src> 去加载,拿到的是一整页 HTML,不是图。差一个 i. 和扩展名,结果天差地别。

分支四:Referrer-Policy 把你自己坑了?

比较隐蔽的一种。如果你的页面设了 Referrer-Policy: no-referrer,浏览器加载图片时完全不发 Referer。有些防盗链配置是「空 Referer 一律挡」,于是你反而被自家的隐私设置挡在门外。实测下来,这种案例通常出现在很在意隐私、把 meta referrer 关死的站。

动手诊断:DevTools 与 curl 两招定位

理论讲完,实际怎么查?我固定用两个工具,五分钟内能定位九成的破图。

第一招:DevTools Network 面板

打开浏览器开发者工具(F12),切到 Network,刷新页面,在过滤器打图片文件名。点进那条请求,看三个东西:

  • Status:是 403、404 还是 200?
  • Response Headers 的 Content-Type:是 image/* 还是 text/html?
  • Request Headers 的 Referer:实际发出去的是什么?空的还是你的域名?

三个看完,根因大概就浮出来了。

第二招:curl 手动控制 Referer

DevTools 看得到现象,但要验证「到底是不是防盗链」,curl 最干脆。你可以手动塞任意 Referer,看服务器反应怎么变:

# 完全不带 Referer(模拟直接开图)
curl -I "https://example.com/photo.jpg"

# 带一个「假装来自来源站自己」的 Referer
curl -I -H "Referer: https://example.com/" "https://example.com/photo.jpg"

# 带一个「来自你的外部站」的 Referer
curl -I -H "Referer: https://your-blog.com/" "https://example.com/photo.jpg"

判读方式很直观。如果第一、三个回 403,但第二个回 200——恭喜,实锤防盗链。服务器只认来源站自己的 Referer,其他一律挡。如果三个都 200,那破图就跟防盗链无关,回头查你的网址或 CSP。

我实测的习惯是三条一起跑,对照结果比单看一条清楚太多。这就是为什么 curl 比在浏览器里瞎点有效率。

国内常见服务的防盗链行为,尤其要小心这几个

不同服务的默认脾气差很多,国内几个大平台的防盗链尤其凶。下面是这几年搬图踩下来的观察,实际配置各家可能随时调整,但大方向如此。

服务类型 默认是否防盗链 空 Referer 行为 适合外站直链?
微博图床(sinaimg) 开 常挡 不行,随时封
百度网盘 / 微云分享链接 严格 挡 不行,天生不是干这个的
简书 / 知乎正文图 开 挡 不行,只服务站内
企业级 CDN(可设白名单) 可开可关 可设放行或挡 设对就可以
部分免费图床 常开 常挡 常被挡
主打分享的图床 通常关 放行 可以,这才是它存在的意义

重点是几个国内大站。很多人图省事,把微博里某张图右键「复制图片地址」拿去别处贴,一开始能显示,过阵子就集体变破图——因为 sinaimg 的防盗链会挡非微博来源的请求,而且策略随时收紧。百度网盘、微云更别提,它们的分享链接背后是权限校验加登录验证,压根不是给「图片直链」用的。简书、知乎的正文图同理,只服务自家站内。

想拿这些图去别处贴,基本是死路一条。而主打「分享」的图床,防盗链默认是关的——它的存在意义就是让你的图能稳定被外站加载到。这两类千万别搞混。

Referrer-Policy 的陷阱:连浏览器都可能反过来坑你

前面提过一种隐蔽状况,这里展开讲,因为它最容易让人 debug 到怀疑人生。

Referrer-Policy 是页面(发出请求那一方)可以设置的头。它决定浏览器要发出多少 Referer 信息。值有好几种:

  • no-referrer:完全不发。
  • origin:只发来源域名。
  • strict-origin-when-cross-origin:跨域只发域名、降级到 HTTP 就不发(现代默认值)。
  • unsafe-url:连完整路径都发(不建议,会漏隐私)。

矛盾点在这里。防盗链要靠 Referer 判断来源,但隐私策略却鼓励少发甚至不发 Referer。当一个站基于隐私设了 no-referrer,它去加载任何有防盗链、又「空 Referer 一律挡」的图,就会全部破掉。

我线上翻过一次车就是这种——某个很重视隐私的站,全站挂了 no-referrer,结果所有外链图全破。当时我还以为是图床挂了,查了半天才发现是自己的 meta 设置把 Referer 掐死了。这个坑不容易想到,因为「加强隐私」听起来怎么会坑到自己?

正确做法:别 hotlink 别人的图

排错到最后,你会发现一个残酷事实:只要图不是你自己托管的,任何「别站的图」都可能在你无法控制的时刻消失。对方改防盗链、换网址、删文件、甚至整站关掉,你的页面就跟着破。

真正稳的做法只有两条。

第一,把图重新托管到自己能控制的地方。 别直接嵌别人的网址。把图下载下来、上传到你自己的空间或一个允许外链的图床,改用那个稳定网址。从架构角度看,这一步的本质是把你页面的可用性,从别人的服务器手上拿回到自己手上——只要来源不是你能掌控的,对方任何一次防盗链调整、网址结构改版、甚至整站下线,都会直接反映成你页面上的破图,而且你连预警都收不到,往往是读者反馈才知道翻车了。如果你手上已经有一整批散落在别人域名的旧链接要一次搬干净,我另外写过一篇 图片链接批量替换的完整 SOP,用脚本扫出全站旧网址一次替换,比手动一张张换省事太多。能控制的来源,才是稳的来源。

第二,选一个防盗链默认关闭的图床。 很多免费图床为了省带宽会挡外链,贴到论坛或博客就破给你看。要外链,就挑一个明确允许直链的服务。

这也是我们做 lpic.cc 时的一条原则:上传后给你的是稳定的图片直链网址,不默认挡外站,让你贴到论坛、博客、Discord 都能正常显示,不会莫名其妙变 403。需要私密的图,也能用密码保护控制谁看得到。想试的话,免费上传 一张图,把链接贴到别的页面测一下就知道稳不稳。

说实话也得诚实讲限制:目前免费方案的图有 30 天保存期,不是永久存档,而且服务靠广告营收支撑。长期典藏或商用大量图库,你该评估付费的专业方案,或自己搭建有备份的存储。工具挑对场景才有意义——这点我踩过雷才学乖。

常见问题 FAQ

Q:为什么同一个图片链接,我自己开得起来,贴到别站就破?

因为你「直接开图」时 Referer 是空的、或来自允许的来源,防盗链放行。贴到别站后,Referer 变成那个外部域名,不在白名单,就被挡成 403。同一个网址、不同的 Referer,结果完全不同。

Q:403 和破图是同一件事吗?

不是。403 是服务器明确拒绝(状态码 403),破图只是浏览器「画不出图」的画面表现。403 会造成破图,但破图也可能来自网址错、Content-Type 错、CSP 挡加载等其他原因。先看状态码才知道是哪种。

Q:把页面设成 Referrer-Policy: no-referrer 能绕过防盗链吗?

有时候可以,有时候反而更惨。如果对方的防盗链是「空 Referer 放行」,不发 Referer 确实能过。但如果对方是「空 Referer 一律挡」,你反而全破。这招不可靠,别当正解用。

Q:微博的图片地址复制出来贴到别处,为什么老是失效?

因为 sinaimg 有防盗链,会挡非微博来源的请求,策略还随时收紧。百度网盘、微云、简书、知乎的正文图同理,都只服务站内。想外链,把图重新上传到一个允许直链的图床,用它给的直链网址。

Q:怎么快速判断一个图床能不能外链?

上传一张测试图,拿它的直链网址,用 curl -I -H "Referer: https://google.com/" 跑一下。回 200 就是允许外链,回 403 就是有防盗链、别拿来贴外站。三十秒验完。

References

#防盗链#hotlink protection#403 Forbidden#Referer#Referrer-Policy#CDN#图片直链
H

作者

Harvey Zhang

联合创始人兼 CTO

后端工程师出身,从系统架构角度深度解析图片托管服务的技术实现。