You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取单个S3文件创建事件?多客户端上传多事件问题

嘿,这个问题我之前帮好几个开发者处理过,咱们先拆解下为什么会出现这种情况,再给你靠谱的解决办法:

为什么会触发多个ObjectCreated事件?

这种情况大多是因为你用的SFTP(或其他上传客户端)的上传逻辑导致的:很多客户端会先创建一个0字节的占位文件(用来锁定上传路径,避免冲突),然后再逐步写入文件内容,最后可能通过重命名或二次写入完成上传流程。这就会让S3连续触发多次对象创建事件:

  • 第一次是创建占位文件的ObjectCreated:Put(大小为0)
  • 后面两次通常是文件内容写入完成后的ObjectCreated:Put,或者如果客户端用了重命名操作,可能会触发ObjectCreated:Copy + ObjectCreated:Put(具体取决于客户端实现)
怎么过滤无效的0字节事件,只获取真正的文件完成通知?

给你三个可行的方案,按推荐程度排序:

方案1:在S3事件通知里直接过滤(最省资源,优先用)

S3本身支持在事件配置里添加对象大小过滤条件,直接把0字节的事件拦在源头:

  1. 打开S3控制台,进入目标存储桶的「属性」→「事件通知」
  2. 编辑已有的通知规则(或者新建规则)
  3. 在「事件类型」里勾选你需要的ObjectCreated相关类型(比如Put、Copy、CompleteMultipartUpload)
  4. 找到「高级条件」板块,添加对象大小大于0字节的过滤规则:
    • 选择「对象大小」→「大于」→ 输入0
  5. 保存规则即可

这样S3只会把大小>0的对象创建事件推送到你的SNS主题,直接跳过那些占位的0字节文件事件。

方案2:在SNS消息的消费端处理

如果因为权限或其他限制没法修改S3的事件配置,那可以在消费SNS消息的代码里做过滤:

  • 解析SNS消息中的S3事件内容,提取object.size字段
  • 只处理size > 0的消息,直接忽略0字节的占位文件

给你一段Python伪代码参考:

import json

def handle_sns_message(sns_message):
    # 解析SNS外层消息
    sns_payload = json.loads(sns_message)
    # 解析内部的S3事件内容
    s3_event_data = json.loads(sns_payload['Message'])
    
    for record in s3_event_data['Records']:
        object_key = record['s3']['object']['key']
        object_size = int(record['s3']['object']['size'])
        
        if object_size > 0:
            # 这里写你处理有效文件的逻辑
            print(f"开始处理新文件: {object_key},大小: {object_size}字节")
        else:
            # 跳过0字节的占位文件
            print(f"忽略0字节占位文件: {object_key}")

方案3:用Lambda做中间层统一过滤

如果你的多个存储桶都有这个需求,或者SNS后面还要对接其他服务,你可以加一个Lambda函数作为中间层:

  1. 把S3的事件通知目标改成这个Lambda函数,而不是直接推SNS
  2. 在Lambda里过滤掉所有0字节的对象事件
  3. 只把符合条件的有效事件推送到你的SNS主题

这样可以统一处理所有存储桶的过滤逻辑,不用逐个桶修改配置,扩展性更强。

额外小提示

如果有些客户端用了S3的分块上传功能,那文件上传完成时会触发ObjectCreated:CompleteMultipartUpload事件,这个事件对应的肯定是完整的文件。你可以在S3事件配置里单独勾选这个事件类型,再结合大小过滤,能更精准地捕获完整的上传完成事件。

内容的提问来源于stack exchange,提问作者Kyle Heuton

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 08:27:07