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

通过单次触发Lambda将S3中Zip文件内容分发至多个CloudFront URL

解决方案概述

完全可以实现你的需求,核心流程是:当Zip文件上传到指定S3存储桶时自动触发Lambda函数,Lambda完成Zip解压后将内部资源同步到关联CloudFront的目标S3存储桶/路径,最终通过对应CloudFront URL访问这些资源。

步骤1:配置S3自动触发Lambda

  • 创建或复用Lambda函数(推荐用Python/Node.js,处理Zip解压逻辑更便捷)
  • 在Lambda控制台的「触发器」模块添加S3触发器:
    • 选择存放Zip文件的源S3桶
    • 触发事件类型选择s3:ObjectCreated:*,若需仅触发Zip文件上传,可在「过滤条件」中添加后缀.zip
    • 为Lambda执行角色配置精细权限(避免过度授权):
      {
          "Version": "2012-10-17",
          "Statement": [
              {
                  "Effect": "Allow",
                  "Action": "s3:GetObject",
                  "Resource": "arn:aws:s3:::你的源Zip存储桶/*"
              },
              {
                  "Effect": "Allow",
                  "Action": "s3:PutObject",
                  "Resource": [
                      "arn:aws:s3:::CloudFront关联桶1/*",
                      "arn:aws:s3:::CloudFront关联桶2/*"
                  ]
              },
              {
                  "Effect": "Allow",
                  "Action": "logs:CreateLogGroup",
                  "Resource": "arn:aws:logs:你的区域:你的账号ID:*"
              },
              {
                  "Effect": "Allow",
                  "Action": [
                      "logs:CreateLogStream",
                      "logs:PutLogEvents"
                  ],
                  "Resource": "arn:aws:logs:你的区域:你的账号ID:log-group:/aws/lambda/你的Lambda函数名:*"
              }
          ]
      }
      

步骤2:Lambda核心逻辑实现

以Python为例,核心功能包括下载Zip、解压、按规则分发文件到对应CloudFront关联桶:

import boto3
import zipfile
import os
import traceback

s3 = boto3.client('s3')

# 定义文件与目标CloudFront关联桶的映射规则
FILE_TO_BUCKET_MAP = {
    "a.jpg": "cloudfront-bucket-1",
    "b.jpg": "cloudfront-bucket-2",
    "c.jpg": "cloudfront-bucket-1",
    # 可根据文件名前缀、类型扩展规则,比如所有png文件到bucket-3
}
DEFAULT_TARGET_BUCKET = "default-cloudfront-bucket"

def lambda_handler(event, context):
    try:
        # 提取S3上传事件中的文件信息
        record = event['Records'][0]['s3']
        source_bucket = record['bucket']['name']
        zip_object_key = record['object']['key']
        
        # 下载Zip到Lambda临时存储(上限512MB,超量需挂载EFS)
        zip_local_path = f"/tmp/{os.path.basename(zip_object_key)}"
        s3.download_file(source_bucket, zip_object_key, zip_local_path)
        
        # 解压Zip到临时目录
        extract_dir = "/tmp/unzipped"
        os.makedirs(extract_dir, exist_ok=True)
        with zipfile.ZipFile(zip_local_path, 'r') as zip_ref:
            zip_ref.extractall(extract_dir)
        
        # 遍历解压后的文件,按规则上传到目标桶
        for root, _, files in os.walk(extract_dir):
            for filename in files:
                local_file_path = os.path.join(root, filename)
                # 匹配目标桶,无匹配则用默认桶
                target_bucket = FILE_TO_BUCKET_MAP.get(filename, DEFAULT_TARGET_BUCKET)
                # 上传文件,保持原文件名作为S3键(确保CloudFront URL对应)
                s3.upload_file(local_file_path, target_bucket, filename)
        
        # 清理临时文件(可选,Lambda执行完会自动清空/tmp)
        os.remove(zip_local_path)
        for root, _, files in os.walk(extract_dir):
            for f in files:
                os.remove(os.path.join(root, f))
        os.rmdir(extract_dir)
        
        return {"statusCode": 200, "body": "Zip解压分发完成"}
    
    except Exception as e:
        # 记录错误日志到CloudWatch
        print(f"执行失败: {str(e)}")
        print(traceback.format_exc())
        return {"statusCode": 500, "body": f"执行失败: {str(e)}"}

步骤3:CloudFront关联目标S3桶

  • 为每个目标S3桶创建CloudFront分发:
    • 源设置选择对应的S3存储桶(推荐使用OAI访问控制,避免S3直接公开访问)
    • 默认缓存行为配置允许GET/HEAD请求,按需设置缓存策略
    • 等待CloudFront部署完成后,即可通过其域名访问对应文件(如https://xxx.cloudfront.net/a.jpg)

关键注意事项

  • Zip大小限制:Lambda默认临时存储为512MB,若Zip文件超量,需为Lambda挂载Amazon EFS扩展存储
  • 分发规则扩展:可通过文件名前缀(如img-*)、文件类型(如.png)等逻辑批量匹配目标桶,无需逐个文件配置
  • 错误处理:Lambda中需添加异常捕获,将错误日志输出到CloudWatch,便于排查问题
  • CloudFront缓存:若需新文件立即生效,可在Lambda中添加CloudFront缓存失效逻辑(需额外配置IAM权限)

内容的提问来源于stack exchange,提问作者Prathap Parameswar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 08:55:15