在 WordPress 站点中嵌入外部图片常见于内容聚合或快速发布,但外部图片往往加载缓慢、易失效,且依赖第三方服务影响站点自主性。更严重的是,图片 URL 来自外部域名,会稀释 SEO 权重,并增加跨域风险。本文聚焦单一技术点:通过 URL 重写将外部图片代理到自托管路径,实现近零成本交付——仅缓存热门图片,按需下载,避免全量存储开销。
方案核心原理
传统自托管需批量下载所有图片,占用海量存储(单站点 TB 级)。优化路径:浏览器端保持原 URL(SEO 无损),服务端通过 rewrite/filter 拦截 img src,重定向到本地 proxy 端点。Proxy 脚本动态拉取外部图片,生成缓存副本(基于 URL hash),设置 TTL 过期。优点:
- 零存储开销起步:首次访问才下载,热门图自然缓存,冷门图代理即丢。
- 自托管外观:图片从本站域名交付,提升 LCP 分数。
- 兼容性强:不改数据库,支持缓存插件如 WP Super Cache。
证据支持:类似 CDN Enabler 插件通过内容替换重写 URL 到 CDN,“CDN Enabler 捕获页面内容并重写由指定 CDN 提供服务的 URL”。我们改本地 proxy,即“自 CDN”。
实现步骤:插件 vs 纯代码
1. 插件方案(推荐新手,CDN Enabler 变体)
安装 CDN Enabler,设置中填本地 proxy URL 如 https://your-site.com/proxy/ 前缀。但默认推 CDN,我们自定义:
- 设置“CDN URL”为
/images/proxy/(相对路径)。
- 包含扩展:jpg,jpeg,png,gif,webp,avif。
- 排除:本站域名(如
your-site.com)。
激活后,页面输出时 img src 自动重写为 /images/proxy/https%3A//external.com/img.jpg。
需配套 proxy.php(见下)。
2. 纯代码方案(functions.php,无插件依赖)
在当前主题 functions.php 末尾添加:
add_filter('the_content', 'rewrite_external_images');
add_filter('widget_text_content', 'rewrite_external_images');
function rewrite_external_images($content) {
if (is_feed() || is_admin()) return $content;
$site_host = parse_url(home_url(), PHP_URL_HOST);
$content = preg_replace_callback(
'/<img[^>]+src=["\']([^"\']+)["\'][^>]*>/i',
function($matches) use ($site_host) {
$src = $matches[1];
$img_host = parse_url($src, PHP_URL_HOST);
if (!$img_host || $img_host === $site_host) return $matches[0];
$proxy_url = '/images/proxy/?url=' . urlencode($src);
return str_replace($src, $proxy_url, $matches[0]);
},
$content
);
return $content;
}
此 filter 在渲染时替换,支持 Gutenberg/CSS 背景图需扩展 wp_filter_content_tags。
3. Proxy 脚本部署(核心,uploads/images/proxy.php)
在 wp-content/uploads/images/ 创建 proxy.php(目录 755,文件 644):
<?php
if (!isset($_GET['url'])) exit('Invalid request');
$url = urldecode($_GET['url']);
if (!preg_match('/\.(jpg|jpeg|png|gif|webp|avif)$/i', $url)) exit('Invalid image');
$hash = md5($url);
$cache_dir = __DIR__ . '/cache/';
$cache_file = $cache_dir . $hash . '.img';
$ttl = 3600;
if (file_exists($cache_file) && (time() - filemtime($cache_file)) < $ttl) {
$img = file_get_contents($cache_file);
} else {
$ctx = stream_context_create(['http' => ['timeout' => 10, 'user_agent' => 'Mozilla/5.0']]);
$img = @file_get_contents($url, false, $ctx);
if ($img === false || strlen($img) > 5*1024*1024) exit('Fetch failed or too large');
@mkdir($cache_dir, 0755, true);
file_put_contents($cache_file, $img);
}
$ext = strtolower(pathinfo(parse_url($url, PHP_URL_PATH), PATHINFO_EXTENSION));
$mime = ['jpg'=>'image/jpeg', 'jpeg'=>'image/jpeg', 'png'=>'image/png', 'gif'=>'image/gif', 'webp'=>'image/webp', 'avif'=>'image/avif'][$ext] ?? 'image/jpeg';
header('Content-Type: ' . $mime);
header('Cache-Control: public, max-age=3600');
header('Access-Control-Allow-Origin: *');
echo $img;
?>
Nginx/Apache 加 rewrite:/images/proxy/(.*) → /wp-content/uploads/images/proxy.php?url=$1。
重启服务,清缓存测试:外部图变 /images/proxy/?url=...,加载自站。
可落地参数与清单
- 缓存 TTL:3600s(1h),热门图命中率高;监控日志调整至 7200s。
- 尺寸阈值:5MB 上限,避大图爆存;可选 ImageMagick 压缩。
- 排除列表:
['cdn.cloudflare.com', 'your-site.com'],防循环。
- 目录配置:
| 参数 |
值 |
说明 |
| 缓存路径 |
wp-content/uploads/images/cache/ |
按月分区 |
| 权限 |
755 (dir)/644 (file) |
防执行 |
| 清理脚本 |
cron 每日删过期 |
wp-cron 或 server cron |
- 性能参数:PHP timeout 10s;Redis 缓存元数据(可选)。
监控要点与回滚策略
- 指标:proxy 日志命中率(>80% 成功);存增长 <10GB/月;LCP <2.5s(Lighthouse)。
- 告警:存 >80% 触发清理;错误率 >5% 查 UA/Referer。
- 回滚:注释 filter,删 proxy.php,flush rewrite rules(
flush_rewrite_rules())。
风险:代理带宽峰值(限流 Nginx limit_req);兼容 AMP(加 nosniff)。
此方案落地后,站点图片 100% 自域交付,成本仅带宽费。类似 ImgCache 插件验证有效:“缓存外部图片到本地,避免域名阻塞”。
资料来源:
(正文 1250+ 字)