今天下午整理博客时,突然发现 Typora 里所有通过 PicGo 上传到 Cloudflare R2 的图片全部变成了裂图。浏览器直接访问图片链接返回 403,但 PicGo 的上传日志显示 success。经过一番排查,最后发现坑在 PicGo 的 outputURLPattern 配置上——不是图床挂了,是 URL 根本没拼对。
症状:上传成功,Typora 不渲染
事情是这样的:
- PicGo 里配置了 Cloudflare R2(通过 S3 兼容 API)。
- 点击上传,PicGo 提示成功,返回了一个链接。
- 把链接贴进 Typora,结果只显示一行蓝色文字,或者干脆是裂图。
我下意识以为是图床挂了,因为返回的域名长这样:
https://xxxassets.hashcode.r2.cloudflarestorage.com/2026/07/xxx.png但诡异的是,我用 Cloudflare 给 R2 绑定的公开访问域名(https://pub-hashcode.r2.dev)去拼接同样的路径,浏览器里是可以正常打开的。
也就是说:图床没挂,是 PicGo 吐出来的 URL 有问题。
排查:到底是哪一层在掉链子
我一步步做了隔离验证:
| 验证项 | 结果 |
|---|---|
| 浏览器直接访问 R2 的 S3 API 域名 | 403,因为 R2 的 r2.cloudflarestorage.com 是私有端点,默认不对外公开访问 |
浏览器访问公开域名 r2.dev + 同样的路径 | 200,图片正常显示 |
Typora 里把链接改成 r2.dev 域名 | 依然不渲染 |
| 检查 PicGo 自定义域名配置 | 发现只填了 https://pub-xxx.r2.dev,上传后返回的 URL 只有域名,没有后面的文件路径 |
到这里,问题拆成了两个:
- 域名不对:应该用
r2.dev公开域名,而不是cloudflarestorage.com私有端点。 - URL 拼接不全:PicGo 只返回了域名根地址,缺少
/2026/07/xxx.png这一段。
根因:outputURLPattern 的占位符理解错了
PicGo 的 S3 插件文档里明确写了:旧的 urlPrefix、urlSuffix 已经废弃,请使用 outputURLPattern。
我最初的 outputURLPattern 配置是这样的(错的):
https://pub-hashcode.r2.dev/{md5}.{extName}同时我的 uploadPath 配置是:
{year}/{month}/{md5}.{extName}结果上传后 PicGo 返回了:
https://pub-hashcode.r2.dev/2026/07/{md5}.png{md5} 被原样输出了,没有替换成实际的哈希值。
问题的核心:outputURLPattern 并不支持 {md5} 占位符。
文档里写得清楚,outputURLPattern 支持的变量是这些:
| 占位符 | 说明 |
|---|---|
{path} | 完整路径,等于 {dir}/{uploadedFileName} |
{uploadedFileName} | 上传后的文件名(含扩展名) |
{dir} | 上传目录 |
{protocol}、{host}、{port} | URL 组成部分 |
{md5}、{year}、{month} 这些只在上传路径 uploadPath 里有效。当文件已经被命名为 {md5}.{extName} 并上传到 {year}/{month}/ 目录后,它在输出模板里的身份已经变成了 {uploadedFileName},所在目录变成了 {dir}。
所以我在 outputURLPattern 里写 {md5},PicGo 根本不认,直接原样输出了字符串 {md5}。
修复:用 {path} 一把梭
正确的 outputURLPattern 应该是:
https://pub-hashcode.r2.dev/{path}对应的完整配置如下:
| 配置项 | 值 |
|---|---|
uploadPath | {year}/{month}/{md5}.{extName} |
endpoint | https://...r2.cloudflarestorage.com |
customUrl | https://pub-hashcode.r2.dev |
outputURLPattern | https://pub-hashcode.r2.dev/{path} |
保存后重新上传,PicGo 返回的链接变成了:
https://pub-hashcode.r2.dev/2026/07/xxxxxx.pngTypora 里立刻正常渲染。
下图展示PicGo中的配置页面:

教训
-
R2 的 S3 API 端点 ≠ 公开访问端点。
*.r2.cloudflarestorage.com是给程序调用的,要给访客看图片,必须绑定*.r2.dev或使用自定义域名,并在 PicGo 里通过outputURLPattern输出正确的公开地址。 -
uploadPath和outputURLPattern的占位符是两回事。{md5}、{year}只在定义上传目录和文件名时可用;输出 URL 时,文件已经落地,要用{path}、{uploadedFileName}、{dir}来引用。 -
裂图不一定是图床挂了。先拿浏览器直接访问图片 URL,确认是权限问题、路径问题,还是 Markdown 语法问题,能少绕很多弯路。