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

基于AWS Chalice与Lambda构建S3图片下载API的部署问题排查

问题描述

我通过部署在Lambda上的AWS Chalice构建图片下载API,图片存储于私有AWS S3桶中。由于需要至少1个月长期可用的下载链接,未使用S3预签名URL。本地运行Chalice时下载的图片可正常打开,但部署到AWS后下载的图片无法打开。

代码实现

@app.route("/img/download", methods=["GET"])
def download_image_api():
    def download_img():
    
    bucket = "my-bucket-name"
    key = "my-key-name"
    filename = "imgae-file-name"
    filepath = f"/tmp/{filename}"

    # download imgae to lambda
    s3 = boto3.client(
        resource="s3",
        region_name=config.AWS_REGION_NAME,
        aws_access_key_id=config.ACCESS_ID,
        aws_secret_access_key=config.SECRET_KEY
    )
    s3.download_file(bucket, key, filepath)

    # build headers
    file_size = os.path.getsize(filepath)
    headers = {
        'Content-Type': 'application/octet-stream',
        'Content-Disposition': f'attachment; filename={filename}',
        'Content-Length': str(file_size)
    }

    # build body
    f = open(filepath, 'rb')
    body = f.read()

    return Response(body=body, headers=headers)

错误现象

部署到AWS后下载的图片无法打开,文件呈现损坏状态。

解决方案

1. 修复代码语法与逻辑错误

  • 删除多余且未调用的空函数download_img(),调整代码缩进
  • 修正boto3.client()初始化参数:第一个参数是服务名称,不是resource,应直接传"s3"
  • 修正文件名拼写错误imgae-file-name为image-file-name
  • 用with语句打开文件,避免资源泄漏导致读取不完整

修复后代码:

@app.route("/img/download", methods=["GET"])
def download_image_api():
    bucket = "my-bucket-name"
    key = "my-key-name"
    filename = "image-file-name"
    filepath = f"/tmp/{filename}"

    # 初始化S3客户端
    s3 = boto3.client(
        "s3",
        region_name=config.AWS_REGION_NAME,
        aws_access_key_id=config.ACCESS_ID,
        aws_secret_access_key=config.SECRET_KEY
    )
    s3.download_file(bucket, key, filepath)

    # 构建响应头
    file_size = os.path.getsize(filepath)
    headers = {
        'Content-Type': 'application/octet-stream',
        'Content-Disposition': f'attachment; filename={filename}',
        'Content-Length': str(file_size)
    }

    # 读取文件内容
    with open(filepath, 'rb') as f:
        body = f.read()

    return Response(body=body, headers=headers)

2. 检查Lambda权限

确保Lambda执行角色拥有目标S3桶的s3:GetObject权限,否则会导致下载的文件为空或损坏。

3. 优化方案:流式返回(无需临时文件)

为避免/tmp目录限制和文件读写问题,建议直接从S3流式读取并返回响应,提升性能同时减少出错概率:

@app.route("/img/download", methods=["GET"])
def download_image_api():
    bucket = "my-bucket-name"
    key = "my-key-name"
    filename = "image-file-name"

    s3 = boto3.client(
        "s3",
        region_name=config.AWS_REGION_NAME,
        aws_access_key_id=config.ACCESS_ID,
        aws_secret_access_key=config.SECRET_KEY
    )
    s3_response = s3.get_object(Bucket=bucket, Key=key)
    
    headers = {
        'Content-Type': s3_response['ContentType'],  # 使用S3存储的原始文件类型更准确
        'Content-Disposition': f'attachment; filename={filename}',
        'Content-Length': str(s3_response['ContentLength'])
    }
    
    return Response(body=s3_response['Body'].read(), headers=headers)

内容的提问来源于stack exchange,提问作者Eric Wang

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 17:53:20