通过API Gateway-Lambda向S3上传多PDF时如何动态传递文件名
解决API Gateway+Lambda上传S3时动态保留原始文件名的问题
你的问题核心在于代码里把S3的Key硬编码成了"test.pdf",所以不管上传什么文件都会覆盖这个固定名称。要实现保留原始文件名,我们需要让前端把文件名传递过来,然后在Lambda里动态获取并使用它。
步骤1:前端传递文件名
前端在上传文件时,可以通过以下几种方式传递原始文件名:
- 自定义请求头:比如添加
X-File-Name头,值为原始文件名(注意中文文件名建议做URL编码) - URL查询参数:在请求URL后拼接
?filename=xxx.pdf - 请求体JSON:把文件名和base64编码的文件内容一起放在JSON里(比如
{"filename":"xxx.pdf","content":"base64字符串"})
这里我们以自定义请求头为例,因为这种方式比较直观且不破坏现有请求体结构。
步骤2:修改Lambda代码
下面是修改后的代码,重点处理了文件名的获取、编码解码,以及修复了原代码里的小问题(比如statuscode的大小写错误):
import boto3 import base64 from io import BytesIO import json import urllib.parse import logging logger = logging.getLogger() logger.setLevel(logging.INFO) BUCKET_NAME = "你的S3桶名称" # 替换成你实际的桶名 def lambda_handler(event, context): try: s3 = boto3.client("s3") # 获取并解码文件内容 file_content_base64 = event["body"] file_content = base64.b64decode(file_content_base64) # 从请求头获取原始文件名(处理URL编码的中文文件名) raw_filename = event["headers"].get("X-File-Name") if not raw_filename: raise ValueError("请求中未传递文件名,请检查请求头是否包含X-File-Name") # 解码URL编码的文件名(如果前端做了编码) original_filename = urllib.parse.unquote(raw_filename) # 可选:给文件名添加前缀,比如uploads/,方便S3文件分类管理 # s3_key = f"uploads/{original_filename}" s3_key = original_filename # 上传到S3,使用原始文件名作为Key s3.put_object(Bucket=BUCKET_NAME, Key=s3_key, Body=file_content) return { "statusCode": 200, "body": json.dumps(f"文件 {original_filename} 已成功上传到S3") } except Exception as e: error_msg = f"上传文件失败: {str(e)}" logger.error(error_msg) return { "statusCode": 500, "body": json.dumps(error_msg) }
关键注意事项
- 中文文件名处理:如果文件名包含中文,前端最好先对文件名做URL编码(比如用
encodeURIComponent),然后Lambda里用urllib.parse.unquote解码,避免S3里出现乱码文件名。 - API Gateway配置:如果用自定义请求头,需要在API Gateway的CORS配置里把
X-File-Name添加到「允许的请求头」列表,否则前端会遇到跨域错误。 - 文件名合法性:可以额外添加逻辑校验文件名是否合法(比如避免包含特殊字符),防止S3报错或者出现安全问题。
- 避免文件名冲突:如果担心多个用户上传同名文件导致覆盖,可以给文件名加上时间戳或者用户ID前缀,比如
user123/20240520_xxx.pdf。
内容的提问来源于stack exchange,提问作者cloudroy
相关产品推荐
相关产品推荐

