上传图片自动出缩略图:FunctionGraph + OBS 触发器
一、背景:缩略图不该等用户访问时才现做
很多业务要展示图片列表(相册、商品图、头像),原图往往几 MB,直接当列表缩略图又慢又费流量。常见做法是"上传原图时顺手生成一张小图",原图和缩略图分开存,列表用缩略图、详情用原图。如果靠人工或后端定时任务去批量转,要么漏、要么慢。
用 FunctionGraph + OBS 触发器可以做成一个自动流水线:图片一上传到源桶,事件触发函数,函数把原图读出来、缩成指定尺寸、写回缩略图桶(或同桶的 thumb/ 前缀)。全程事件驱动、无需人工。本文讲这条链路怎么搭,重点是函数里怎么处理图片、怎么避免循环触发。
二、链路一览
- 用户/系统把原图上传到源桶
images/前缀; - OBS 产生 PutObject 事件,触发器推给函数,事件带对象 Key;
- 函数从源桶下载原图到内存;
- 用图像处理库缩放到目标尺寸;
- 把缩略图上传到目标桶(或同桶
thumb/前缀); - 返回,流水线结束。
整个过程源桶来一张、缩略图桶多一张,后续展示直接读缩略图,原图只在看大图时才拉。
三、函数里怎么缩图
函数运行时把原图读进内存,用图像处理库(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.jpg→a_300x300.jpg),展示层拼 URL 方便。也方便以后要不同尺寸时再扩。
第五,触发器事件类型。只勾 PutObject/PostObject,别把 Delete 也勾上,否则删原图又触发一次无意义处理。
六、小结
图片上传自动出缩略图,是 OBS 事件触发最实用的例子之一:源桶来图、函数缩、写回缩略图桶、列表直接读小的。配置精髓是"防循环"——缩略图写另一个桶、触发器只监听源前缀、代码里再加一道前缀判断,三层保险。函数处理注意内存上限和格式保留。触发器事件结构和函数依赖打包方式以官方文档为准,照着配好,上传即缩略图就自动化了。
- 点赞
- 收藏
- 关注作者
评论(0)