18 10 月 2026
小程序最烫手的两类数据是图片和文件:用户头像、商品图、聊天图片、表单附件。存服务器本地?带宽先爆、硬盘再爆、备份哭死。正确姿势是对象存储 + CDN + 直传——这篇讲清楚为什么、怎么做。

一、为什么不能存服务器本地

算一笔账就明白。一个电商小程序,日均上传 500 张商品图,平均 2MB:

指标存本地对象存储
日增硬盘1GB0(在云端)
月增硬盘30GB0
下载流量全走服务器带宽走 CDN,服务器零参与
带宽压力5M 带宽 3 人同时下图就满无限并发
备份要连文件一起备,越备越大存储商多副本,天然高可用
单点服务器挂了图全丢服务商 SLA

结论:只要文件量会上涨,就必须对象存储。只有"几十张静态图"的演示项目可以存本地。

二、上传的三种姿势

姿势 A:小程序 → 你的服务器 → 对象存储(中转)

小程序 --上传--> 你的服务器 --转发--> 对象存储

优点:简单,服务端能做格式校验、鉴权、压缩。缺点:流量过你的服务器,大文件高峰期带宽和 CPU 双杀。适合小规模。

姿势 B:小程序 → 对象存储直传(推荐)

小程序 --(拿临时密钥)--> 直接上传到对象存储

优点:服务器只发一个"临时凭证",上传流量完全不经过你的机器——带宽压力清零,还能利用存储商的 CDN 加速。缺点:要配临时密钥(STS)和跨域(CORS)规则。这是生产环境的标准方案。

姿势 C:云开发存储

用微信云开发的 wx.cloud.uploadFile,最省事,但数据在腾讯云上,且走云开发的计费体系——选型对比见小程序云开发 vs 自建后端。

三、姿势 B 完整实现

1. 小程序端:选择文件 + 上传

wx.chooseMedia({
  count: 1,
  mediaType: ['image'],
  sizeType: ['compressed'],
  success: async (res) => {
    const tempFilePath = res.tempFiles[0].tempFilePath
    // 先从自己服务端拿临时上传凭证
    const { data } = await wx.request({
      url: 'https://api.yourdomain.com/sts/token',
      method: 'POST'
    })
    // 直传到对象存储(以腾讯云 COS 小程序 SDK 为例)
    const cos = new COS({
      getAuthorization: (options, callback) => {
        callback({
          TmpSecretId: data.tmpSecretId,
          TmpSecretKey: data.tmpSecretKey,
          SecurityToken: data.sessionToken,
          StartTime: data.startTime,
          ExpiredTime: data.expiredTime
        })
      }
    })
    cos.putObject({
      Bucket: 'your-bucket-1250000000',
      Region: 'ap-guangzhou',
      Key: 'avatar/' + Date.now() + '.jpg',
      FilePath: tempFilePath
    }, (err, result) => {
      if (!err) console.log('上传成功', result.Location)
    })
  }
})

2. 服务端:签发临时凭证

临时密钥用云厂商的 STS 服务(Python/Node/PHP 都有 SDK),核心逻辑:

const STS = require('tencentcloud-sdk-nodejs/tencentcloud/services/sts/v20180813')
const sts = new STS({ /* 用主账号密钥初始化,密钥只存服务端 */ })

app.post('/sts/token', async (req, res) => {
  // 实际项目要校验用户登录态,按用户限频限配额
  const policy = {
    version: '2.0',
    statement: [{
      effect: 'allow',
      action: ['cos:PutObject'],                 // 只给上传权限
      resource: ['qcs::cos:ap-guangzhou:uid/1250000000:bucket-1250000000/avatar/*']
    }]
  }
  const result = await sts.AssumeRole({
    RoleArn: '你的角色ARN',
    RoleSessionName: 'miniapp-upload',
    DurationSeconds: 1800,                        // 短时效,30 分钟
    Policy: JSON.stringify(policy)
  })
  res.json(result.Credentials)
})

权限三原则:只给 PutObject(不给读不给删)、只给 avatar/* 前缀(不给整桶)、短时效(30 分钟内)。主账号密钥永远不出服务端——它出现在小程序代码里的那天,就是桶被搬空的那天。

3. 对象存储配置

  • CORS 规则:允许小程序域名/上传域名的跨源请求,否则上传被浏览器策略拦
  • 防盗链:Referer 白名单,别让别人的站直接引用你的图
  • CDN 加速:开存储商的 CDN,全球下载都快,见CDN 加速配置实战

四、图片处理:上传只是开始

对象存储的杀手锏是图片处理 API,在 URL 后面拼参数就能实时处理:

原图:     https://cdn.yourdomain.com/avatar/123.jpg
缩略图:   https://cdn.yourdomain.com/avatar/123.jpg?imageMogr2/thumbnail/300x
WebP:     https://cdn.yourdomain.com/avatar/123.jpg?imageMogr2/format/webp
质量压缩: https://cdn.yourdomain.com/avatar/123.jpg?imageMogr2/quality/80
水印:     https://cdn.yourdomain.com/avatar/123.jpg?watermark/2/text/xxx

用法:列表页用缩略图、详情页用原图、按需转 WebP——同一张图多场景复用,存储和流量都省。图片优化的完整方法论见网站图片与静态资源优化。

小程序端压缩:wx.compressImage 先压再传,用户流量和上传时间双降:

wx.compressImage({
  src: tempFilePath,
  quality: 80,        // 80 质量肉眼无损
  success: (res) => { /* 用 res.tempFilePath 上传 */ }
})

五、下载与鉴权

对象存储的读取分两种:

模式用途配置
公有读头像、商品图(谁都能看)桶/对象公有读 + CDN
私有读用户身份证、合同、订单凭证私有桶 + 服务端签临时 URL

私有文件的下载链接要服务端按需签发(带时效的预签名 URL),别图省事设成公有读——用户隐私文件公网可遍历是数据泄露的重灾区,处置流程见数据泄露应急响应与合规要点。

六、运维清单

  • [ ] 主账号密钥只在服务端环境变量,不进代码库(用 .env + .gitignore,见Git 仓库与代码泄露防范)
  • [ ] 上传限频限类型(单用户每分钟 N 张,只许 jpg/png/webp)
  • [ ] 单文件大小上限(小程序 uploadFile 本身限 10MB)
  • [ ] 生命周期规则:临时文件 7 天自动清理,别让废弃上传堆成山
  • [ ] 元数据入库:谁传的、什么时候、Key 是什么——数据库和存储对不上账时,元数据是唯一线索
  • [ ] 跨账号容灾:核心文件定期同步到第二个桶/账号,服务商出事故时能恢复

结语

图片存储的黄金法则:上传走直传、下载走 CDN、处理用 URL 参数、权限按对象配。这套方案让服务器彻底从"文件搬运工"里解放出来——机器只跑业务逻辑,带宽和硬盘的压力归零,扩容就是改个桶的事。

需要搭小程序后端,可以看看财富云计算:NAT 型云服务器支持 443 映射,配合对象存储做图片直传,业务服务器 2核2G 就够——图片的事交给云存储,服务器的钱省一半。

延伸阅读
  1. 网站环境怎么选:LNMP 手动 / 宝塔面板 / Docker / 云开发
  2. 问卷表单系统搭建:SurveyKing / Formbricks,数据自己收
  3. 图床搭建:Lsky Pro / Lychee,自托管图片托管方案
  4. 邮件列表搭建:listmonk 自托管 Newsletter,把读者握在自己手里
  5. 文档站点搭建:MkDocs / VuePress / Docsify,产品文档与技术手册方案
  6. RSS 阅读器搭建:FreshRSS 自托管,把信息流拿回自己手里
  7. 短链接服务搭建:Shlink 自托管,链接数据自己掌握
  8. 网站状态监控页搭建:Uptime Kuma,服务器挂了第一时间知道
更多阅读
  1. 上一篇:小程序数据库对接实战:MySQL 选型、连接池与注入防护
  2. 下一篇:小程序性能优化:首屏、setData 与体验分完全指南
发表评论 1