
微博图床防盗链导致全站图片失效:我的应急修复与长期方案(含 s.php)
最近微博图床防盗链策略收紧,导致我站里大量图片(尤其是 sinaimg.cn)直接失效。本文记录一次完整修复过程,方便以后再遇到同类问题时快速恢复。
一、问题现象
- 文章封面和正文图片突然大量挂掉
- 直接访问微博图片链接经常打不开
- 给链接前面加
https://i1.wp.com/有时能显示,但速度偏慢
二、根因分析(为什么会挂)
微博图床(sinaimg.cn)开启或加强了防盗链校验。浏览器直接从你的站点请求这些图片时,Referer/访问路径不符合规则,就会被拦截。
本质上不是 HTML 写错,而是外链图床策略变化。
三、几种常见修复方案对比
1)i1.wp.com 前缀中转(临时可用)
把:
https://tva1.sinaimg.cn/...
改成:
https://i1.wp.com/tva1.sinaimg.cn/...
优点:改动简单
缺点:速度一般,稳定性受第三方策略影响
2)s.php 做 302 跳转到搜狗 CDN(我最终采用)
访问:
/s.php?u=微博原图URL
由 s.php 返回 302 到:
https://img01.sogoucdn.com/net/a/04/link?...
优点:快、实现简单
缺点:依赖第三方跳转链路,偶发不稳定
3)s.php 服务器代理输出图片(最稳)
PHP/cURL 服务器端拉取图片后直接输出 image/*。
优点:显示更稳
缺点:更吃服务器带宽和性能
四、我最终使用的 s.php(纯 302、无缓存、简单快速)
把文件放在网站根目录(与 index.php 同级),文件名 s.php:
<?php
declare(strict_types=1);
// 用法: /s.php?u=https://tvax4.sinaimg.cn/large/xxx.jpg
$u = isset($_GET['u']) ? trim((string)$_GET['u']) : '';
if ($u === '') {
http_response_code(400);
exit('missing u');
}
$u = urldecode($u);
if (!preg_match('#^https?://#i', $u)) {
http_response_code(400);
exit('invalid url');
}
$parts = parse_url($u);
$host = strtolower($parts['host'] ?? '');
// 只允许微博图片域名,防止被滥用
if ($host === '' || !preg_match('/(^|\\.)sinaimg\\.cn$/', $host)) {
http_response_code(403);
exit('forbidden host');
}
// 302 跳转到搜狗 CDN
$target = 'https://img01.sogoucdn.com/net/a/04/link?appid=100520031&w=1920&url=' . rawurlencode($u);
header('Referrer-Policy: no-referrer');
header('Location: ' . $target, true, 302);
exit;
五、文章里怎么写图片
把原图:
<img src="https://tva1.sinaimg.cn/large/xxxx.jpg" />
改为:
<img src="https://你的域名/s.php?u=https://tva1.sinaimg.cn/large/xxxx.jpg" />
例如:
<img src="https://xxx.com/s.php?u=https://tvax4.sinaimg.cn/large/006BNqYCgy1iaunanj9o3j30e80iw0v6.jpg" />
六、快速验收步骤(2 分钟)
- 访问
https://你的域名/s.php,应返回:missing u - 访问
https://你的域名/s.php?u=微博图片URL,应 302 到img01.sogoucdn.com并显示图片 - 把这条 URL 放进文章
<img src="...">,前台刷新检查显示
七、坑
坑 :以为“地址栏能打开”就等于“文章里一定显示”
不完全等价。地址栏直开和 <img> 子资源加载,可能被不同策略影响(Referer/CDN/WAF)。
八、批量替换(把旧的 i0.wp.com 改成 s.php)
先备份数据库!
下面给两个版本:Typecho 和 WordPress。
A. Typecho(我实际用的)
UPDATE typecho_contents SET text = REPLACE( text ,'旧域名地址','新域名地址'); UPDATE typecho_fields SET str_value = REPLACE( str_value ,'旧域名地址','新域名地址');
B. WordPress(给 WP 用户)
START TRANSACTION; UPDATE wp_posts SET post_content = REPLACE( post_content, 'https://i0.wp.com/', 'https://你的域名/s.php?u=https://' ) WHERE post_content LIKE '%https://i0.wp.com/%' AND post_content LIKE '%sinaimg.cn%'; UPDATE wp_postmeta SET meta_value = REPLACE( meta_value, 'https://i0.wp.com/', 'https://你的域名/s.php?u=https://' ) WHERE meta_value LIKE '%https://i0.wp.com/%' AND meta_value LIKE '%sinaimg.cn%'; COMMIT;
注意:如果你的 WP 表前缀不是 wp_,请改成实际前缀。
九、长期建议(避免再次被动)
- 新图尽量不要继续依赖微博图床
- 逐步迁移到自有对象存储(OSS/COS/R2 等)+ CDN
s.php仅作为历史资源过渡方案- 定期抽查文章封面与正文图片可用性
十、结论
这次故障的核心不是程序崩了,而是外链图床策略变了。
- 应急恢复:
s.php302 跳转方案,最快上线 - 稳定优先:后续考虑自建图床,逐步迁移
- 运维关键:批量改库前必须备份,可回滚才安全










