上传图片自动出缩略图:FunctionGraph + OBS 触发器

举报
柠檬-夏日清爽 发表于 2026/09/13 18:50:19 2026/09/13
【摘要】 用 FunctionGraph + OBS 事件触发器,图片一上传就自动生成缩略图写回缩略图桶,列表用小的、详情用原图。含 Pillow 缩图代码,重点讲防循环触发(分桶+前缀+代码判断)与内存/格式注意点。

一、背景:缩略图不该等用户访问时才现做

很多业务要展示图片列表(相册、商品图、头像),原图往往几 MB,直接当列表缩略图又慢又费流量。常见做法是"上传原图时顺手生成一张小图",原图和缩略图分开存,列表用缩略图、详情用原图。如果靠人工或后端定时任务去批量转,要么漏、要么慢。

用 FunctionGraph + OBS 触发器可以做成一个自动流水线:图片一上传到源桶,事件触发函数,函数把原图读出来、缩成指定尺寸、写回缩略图桶(或同桶的 thumb/ 前缀)。全程事件驱动、无需人工。本文讲这条链路怎么搭,重点是函数里怎么处理图片、怎么避免循环触发。

二、链路一览

  1. 用户/系统把原图上传到源桶 images/ 前缀;
  2. OBS 产生 PutObject 事件,触发器推给函数,事件带对象 Key;
  3. 函数从源桶下载原图到内存;
  4. 用图像处理库缩放到目标尺寸;
  5. 把缩略图上传到目标桶(或同桶 thumb/ 前缀);
  6. 返回,流水线结束。

整个过程源桶来一张、缩略图桶多一张,后续展示直接读缩略图,原图只在看大图时才拉。

三、函数里怎么缩图

函数运行时把原图读进内存,用图像处理库(Python 用 Pillow)缩放后回写。示意:

from PIL import Image
import io

def make_thumb(object_body: bytes, size=(300, 300)):
    img = Image.open(io.BytesIO(object_body))
    img.thumbnail(size)                       # 等比缩到 size 内
    buf = io.BytesIO()
    img.save(buf, format=img.format or "JPEG")
    return buf.getvalue()

thumbnail 是等比缩,保证不变形,最长边不超过 size 里较大的那个维度。缩完用 io.BytesIO 存回字节,直接上传,不落盘(函数临时盘小,且没必要落盘)。Pillow 是否预装在函数运行时里、或需打包依赖,以及 OBS SDK 取/存对象的方法,以官方文档为准——有些运行时需要把依赖打进函数包。

四、回写哪里、怎么避免死循环

缩略图写回哪里,直接决定会不会"转着转着停不下来":

  • 写回另一个桶(推荐):缩略图写到 thumb-bucket,源桶的触发器只监听 images/ 前缀,目标桶不挂触发器,绝不会循环。
  • 写回同桶不同前缀:比如源桶 images/,缩略图写 thumb/。这时触发器必须只监听 images/ 前缀,否则缩略图写入 thumb/ 又触发函数、再读缩略图再缩……虽然前缀过滤能挡住,但配置错一个字就死循环,不如分桶干净。
def handler(event, context):
    key = event["Records"][0]["s3"]["object"]["key"]
    if not key.startswith("images/"):     # 双保险:只处理源前缀
        return {"skipped": True}
    body = obs_get(src_bucket, key)
    thumb = make_thumb(body, (300, 300))
    obs_put(thumb_bucket, "thumb/" + key.split("/")[-1], thumb)
    return {"ok": True}

代码里那句 if not key.startswith("images/") 是双保险:即使触发器前缀配错,函数自己也能拦住非源文件,避免无限递归把函数调用次数和费用打爆。

五、几个工程注意点

第一,循环触发是头号雷。上面反复强调,因为一旦发生,缩略图触发缩略图、再缩、再触发,函数调用和存储暴涨还不一定立刻发现。分桶 + 前缀过滤 + 代码内判断,三层防护最稳。

第二,大图内存。函数内存有限,几 MB 的原图没问题,但几十 MB 的图读进内存处理要留意函数内存配置,否则 OOM 失败。极端大图考虑限制处理尺寸或先做流式处理。

第三,格式与原图一致img.save 时格式尽量沿用原图格式(jpg 存 jpg、png 存 png),否则透明 PNG 存成 JPG 会变黑底。上面用 img.format or "JPEG" 就是保格式,PNG 场景别硬转 JPG。

第四,缩略图命名。建议保留原文件名、加尺寸标识(如 a.jpga_300x300.jpg),展示层拼 URL 方便。也方便以后要不同尺寸时再扩。

第五,触发器事件类型。只勾 PutObject/PostObject,别把 Delete 也勾上,否则删原图又触发一次无意义处理。

六、小结

图片上传自动出缩略图,是 OBS 事件触发最实用的例子之一:源桶来图、函数缩、写回缩略图桶、列表直接读小的。配置精髓是"防循环"——缩略图写另一个桶、触发器只监听源前缀、代码里再加一道前缀判断,三层保险。函数处理注意内存上限和格式保留。触发器事件结构和函数依赖打包方式以官方文档为准,照着配好,上传即缩略图就自动化了。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。