squeeze+Cloudflare R2实现博客图片压缩和加载优化

对于博客的图片管理这一块我之前一直做得比较随意,但前两天回看我的文章时发现加载速度惊人地慢…然后我就想起来:我的图片好像都是原图上传的!一篇文章加载几十MB的图片谁来都顶不住啊,于是赶紧把图片优化提上日程。

背景介绍

我原来的做法很简单:写作使用Typora,通过设置和PicGo联动,在PicGo设置Github图床,然后设一个二级域名(比如cdn.cybereal.one) 用CNAME解析到一个jsDelivr的国内镜像,这样基本不用我做什么设置,在编辑器里传一张图就可以之间转为cdn,cyebreal.one开头的网址了。

但这样做有两个问题:一个是我原图上传毫无压缩,这在互联网内容传输是非常错误的选择,因为在网页浏览中一张10MB的原图可能和压缩后300KB的图片观感差异并不太大,但对加载速度的影响是极为显著的,以前看过这么一段话:

网站加载时间每多一秒,将严重损害业务表现。根据多项研究,每增加1秒延迟:转化率会减少7%,页面浏览量减少11%,用户满意度下降16%,甚至会导致10%的用户流失。加载时间超过3秒,可能导致超过53%的移动用户跳出。

虽然个人网站也不是特别在意用户流失(本来也没多少浏览量),但加载速度太慢无论如何都还是很不方便。

此外,原来用的cdn是我在网上随便找的jsDelivr镜像,加载速度和可靠性都不是很有保证。

于是打算在上传前加一个压缩的预处理,以及换一个CDN,研究一番决定使用Cloudflare R2存储桶。

图片压缩

既然之前上传图片的工作流用到了PicGo,它也有丰富的插件生态,那么事情就很好办了。一番搜寻之后我找到了picgo-plugin-squeeze这个插件,它支持本地压缩和在线压缩两种模式,本地使用npm包sharp实现,在线压缩使用色彩笔(昨天我下插件时还是这样,但今天一看作者又更新了一个TinyPNG的在线方案)

这个插件其实功能很完善,该有的都有,但我还希望有两个功能:一个是格式转换,比如压缩的同时把jpg转webp之类的(作者已经更新了),还有自定义分辨率,比如4k的图压一下顺便转1080p,因为想加这两个功能,晚上用codex写了一个小时,但各种原因装不到PicGo里…遂放弃

于是就直接使用这个插件了,图片质量我设为75,其实压缩效果还是不错的,游戏截图可以压缩92%左右

PicGo日志

压缩后游戏截图

于是图片优化的部分就结束了,很简单,就在PicGo装个插件的事

Cloudflare R2

接下来是更换CDN,本来想着换到国内的某些对象存储,比如腾讯云,七牛云OSS之类的,后来看到网上说R2不收流量费,还有免费额度,正好我域名也是托管在CF的,比较方便,就选这个了

第一阶段:在 Cloudflare 创建 R2 存储桶与获取凭证

首先登陆Cloudflare ,接着选择R2对象存储,第一次打开会需要激活R2的计划,要绑个银行卡之类的,不过只要用量不超过A类操作(上传写入之类的)100万次/月B类操作(读取等)1000万次/月,以及每月10GB限额,就不会收费,如果没有银行卡参照这期文章或者docofcard

创建存储桶 (Bucket)

  • 点击“创建存储桶” (Create Bucket)。
  • 名称:起一个你喜欢的名字(比如 my-blog-images)。
  • 位置提示:默认“自动”即可(Cloudflare 会根据上传源自动分配,通常会在亚太地区)。
  • 创建完成后,你会在存储桶概览里看到一个类似于 https://<你的账户ID>.r2.cloudflarestorage.comS3 终结点 (Endpoint) 链接,把它复制下来备用。

获取 API 令牌 (核心钥匙)

  • 回到 R2 的主界面(不要进具体的存储桶),在右上角或者右侧边栏找到 “管理 R2 API 令牌”
  • 点击“创建 API 令牌”。
  • 权限:务必选择 “对象读和写”
  • 指定存储桶:强烈建议只勾选你刚才创建的那个博客专属 Bucket,遵循最小权限原则。
  • TTL:选择“永久”。
  • 创建后,页面会仅显示一次你的秘钥信息。请立刻将 访问密钥 ID (Access Key ID)机密访问密钥 (Secret Access Key) 复制并妥善保存。

第二阶段:绑定自定义域名(关键步骤)

R2 默认会提供一个 *.r2.dev 的公共访问链接,但这个链接经常被墙,且有速率限制。既然你有自己的域名并且托管在 Cloudflare 上,直接绑定自定义域名才是完全体。

  1. 进入你刚才创建的存储桶设置页面。
  2. 找到 “公共访问” (Public Access) -> **“自定义域” (Custom Domains)**。
  3. 点击“连接域”,输入你规划好的图片二级域名(例如 cdn.你的域名.com)。
  4. Cloudflare 会自动在你的 DNS 记录里添加对应的 CNAME 记录,并自动配置 SSL 证书。
  5. 等待几分钟,直到状态显示为“活跃 (Active)”。你的图片访问基础 URL 就是 [https://cdn.你的域名.com](https://cdn.你的域名.com) 了。

第三阶段:打通 PicGo 链路

因为 R2 完美兼容亚马逊 S3 协议,所以我们不需要找专门的 R2 插件,直接用最成熟的 S3 插件即可。

  1. 安装插件 在 PicGo 的插件设置里,搜索并安装 picgo-plugin-s3(认准作者是 wayjam 的那个版本,下载量最高)。
  2. 配置 S3 图床参数 进入图床设置 -> 亚马逊 S3,按照以下规则填写:
    • 应用密钥 ID:填入第一阶段获取的 Access Key ID。
    • 应用密钥:填入第一阶段获取的 Secret Access Key。
    • 桶名:填入你的存储桶名称(例如 my-blog-images)。
    • 上传文件路径:可以写 {year}/{month}/{fileName},这样云端文件会自动按年月归档。
    • 地区:填 auto 或者直接留空。
    • 自定义节点:填入第一阶段获取的 S3 终结点,类似于 https://<账户ID>.r2.cloudflarestorage.com
    • 自定义域名:填入第二阶段绑定的域名,例如 [https://cdn.你的域名.com](https://cdn.你的域名.com)
    • ForcePathStyle:开启(设为 true 或勾选)。这是兼容第三方 S3 服务的关键开关。
    • RejectUnauthorized:关闭(设为 false,避免某些本地证书校验问题)。
    • ACL 访问控制列表public-read
  3. 设为默认图床 保存配置,并将其设为默认图床。

结束!

如果不出问题的话,做完这两步,配合Typora联动PicGo,就可以实现向Typora粘贴图片→自动通过PicGo上传图片→压缩图片→传到R2存储桶→自动返回链接的模式了,大幅减少网站加载速度,收工!