图片存储和普通文件存储不完全一样。
普通文件更关注上传、下载、权限和保存;图片还要关注尺寸、格式、压缩、裁剪、响应式、CDN、缓存、懒加载、缩略图和页面性能。
如果你的产品里只有少量后台附件,用普通对象存储就够了。但如果图片会直接影响用户体验、SEO、页面速度和带宽成本,就需要更认真地设计图片存储方案。
本文参考了几类官方文档和产品资料:
- Cloudinary Image Transformations
- Cloudinary Image Optimization
- ImageKit Image Transformations
- ImageKit Image Optimization
- Cloudflare Images Transformations
- Cloudflare R2
- Amazon S3 Presigned URLs
先区分图片类型
不是所有图片都应该用同一种方案。
产品里的图片大致可以分成四类:
公开图片:头像、封面、文章配图、商品图
私有图片:证件、合同截图、内部附件、用户隐私图
需要处理的图片:缩略图、裁剪图、压缩图、水印图
临时图片:导入预览、AI 生成中间图、短期分享图
公开图片更关注访问速度和缓存;私有图片更关注权限和临时访问;需要处理的图片更关注变体管理;临时图片更关注生命周期和自动清理。
先分类型,再选技术,否则很容易把简单问题复杂化,或者把敏感图片做成公开资源。
方案一:对象存储 + CDN
最基础的方案,是把图片存到对象存储,再通过 CDN 分发。
常见组合包括 S3 + CloudFront、R2 + Cloudflare、OSS + CDN、COS + CDN 等。
这种方案适合你想自己控制存储结构、权限、成本和处理流程。上传可以用预签名 URL,访问可以走公共 CDN 或私有临时 URL。
优点:
成本可控
结构清楚
适合大量原图保存
容易和已有文件系统统一
缺点:
图片压缩、裁剪、格式转换要自己处理
缩略图和多尺寸图需要自己生成
缓存策略要自己设计
运维和调试成本更高
如果你的产品图片量不大,或者工程能力强,这个方案很稳。
方案二:图片云服务
图片云服务专门处理图片上传、转换、优化和分发。
Cloudinary 官方文档展示了基于 URL 的图片 transformation 能力;ImageKit 也提供 URL 参数方式做图片 transformation 和 optimization;Cloudflare Images 提供图片压缩、格式转码、尺寸调整和裁剪等能力。
这类服务的价值是:你不用自己写大量图片处理逻辑。
适合场景:
objectivec
产品强依赖图片体验
需要多尺寸、多格式、多裁剪
需要快速上线
希望自动优化 WebP / AVIF 等格式
希望减少图片处理运维
缺点是成本、平台绑定和 transformation 计费规则需要认真评估。
方案三:先对象存储,再接图片优化层
很多产品可以采用折中方案。
原图放在对象存储里,前面接一层图片优化服务或 CDN transformation。这样你既保留原始文件控制权,又能获得图片优化能力。
比如原图在 S3 或 R2,访问时通过 Cloudflare、ImageKit、Cloudinary 或自建图片处理服务生成不同尺寸。
这个方案适合图片越来越重要,但你还不想把所有资产完全托管到一个图片平台。
关键是要设计好源图、派生图、缓存和失效策略。
公开图片和私有图片分开
公开图片可以长时间缓存,甚至走公共 CDN。比如头像、文章封面、产品截图、公开模板图。
私有图片不能只靠"URL 很长"来保护。用户访问前要经过权限校验,再生成临时 URL,或者通过受控下载接口返回。
尤其是:
发票图片
证件图片
合同截图
内部文档截图
用户上传的私密图片
这些图片应该放在私有 bucket 或私有路径里,不要和公开图片混用。
原图要不要保留
很多图片系统会保留原图,再生成展示图。
保留原图的好处是:以后可以重新处理、生成新尺寸、换压缩算法、支持新格式。缺点是占用更多存储成本。
如果图片是用户的重要资产,建议保留原图。如果只是临时预览图、一次性缩略图、缓存图,可以只保留处理后版本,或者设置生命周期自动删除。
判断标准是:未来是否需要重新生成?用户是否把它当资产?删除后能否恢复?
图片变体要有规则
图片变体是指不同尺寸、不同格式、不同裁剪方式的图片。
比如:
avatar_64
avatar_256
cover_1200x630
thumbnail_320
original
不要在代码里随手生成各种尺寸。尺寸越随意,缓存越乱,存储越难清理,成本越难估算。
早期可以定义固定几类尺寸:头像、小缩略图、大缩略图、列表图、详情图、分享图。需要新尺寸时再增加。
格式和压缩会影响性能
图片性能对页面速度影响很大。
JPEG、PNG、WebP、AVIF 各有适合场景。现代图片服务通常能根据浏览器能力自动选择更合适的格式。
Cloudinary 和 ImageKit 的官方优化文档都强调图片优化对 Web 性能的重要性。Cloudflare Images 文档也提到可以压缩图片、转码为高效格式、按不同设备尺寸调整图片。
你不一定要手工处理所有格式,但要确保图片系统能支持自动优化。
缓存和失效要提前设计
公开图片通常应该强缓存。问题是图片更新时怎么办?
常见做法是使用带版本的 URL:
bash
/images/avatar/user_123_v2.webp
/images/product/abc?v=20260531
或者每次更新生成新的 object key,而不是覆盖旧文件。
如果你直接覆盖同一个 URL,CDN 和浏览器缓存可能导致用户长时间看到旧图。
图片更新频繁的场景,要特别设计缓存失效策略。
成本不只看存储
图片成本包括:
原图存储
派生图存储
图片处理次数
CDN 流量
回源流量
请求次数
缓存未命中
跨区域访问
有些图片服务按 transformation、存储、带宽或请求量计费。你要提前估算产品的图片访问模式。
如果图片访问量远大于上传量,CDN 和缓存很关键。如果图片处理变体很多,transformation 成本很关键。如果原图很大,压缩和尺寸限制很关键。
一个简单选择规则
可以按下面规则选择:
图片很少、主要是后台附件:对象存储即可
公开图片多、访问量大:对象存储 + CDN
需要大量裁剪压缩格式转换:图片云服务
需要保留控制权又要优化能力:对象存储 + 图片优化层
私有图片较多:私有对象存储 + 临时访问 URL
图片是核心体验:优先选择成熟图片平台
早期不要为了少量图片引入过重系统,也不要在图片已经成为核心体验时继续用临时方案硬撑。
写在最后
图片存储的核心不是"放在哪里",而是"如何被上传、处理、访问、缓存、更新、删除和计费"。
一个稳妥的起点是:原图进对象存储,数据库保存元数据,公开图走 CDN,私有图走临时访问,常用尺寸提前定义,图片优化交给成熟服务或清晰的后台任务。
下一篇,我们继续聊分发能力:CDN 要不要上。
