实现S3跨桶复制的Python3 Lambda无法向CloudFormation返回响应
问题根因
错误出在send_response函数的请求构造逻辑,两个兼容性问题导致urllib无法正确识别请求体类型:
- 手动指定
Content-Length请求头时,取值为未编码的JSON字符串长度,而实际发送的是UTF-8编码后的字节流,二者长度可能不一致,干扰urllib的请求校验逻辑 - 采用重写
Request对象get_method属性的方式修改请求方法为PUT,该写法是Python 2/3.6之前版本的兼容写法,在你使用的Python 3.9运行环境中存在兼容性问题,导致urllib误判请求体类型
修正后的send_response函数代码
def send_response(event, context, response_status, response_data): '''Send a resource manipulation status response to CloudFormation''' response_body = json.dumps({ "Status": response_status, "Reason": "See the details in CloudWatch Log Stream: " + context.log_stream_name, "PhysicalResourceId": context.log_stream_name, "StackId": event['StackId'], "RequestId": event['RequestId'], "LogicalResourceId": event['LogicalResourceId'], "Data": response_data }) # 编码为字节流 response_bdy = response_body.encode('utf-8') LOGGER.info('ResponseURL: %s', event['ResponseURL']) LOGGER.info('ResponseBody: %s', response_body) opener = build_opener(HTTPHandler) # Python3 直接通过method参数指定PUT请求,无需重写get_method request = Request(event['ResponseURL'], data=response_bdy, method='PUT') request.add_header('Content-Type', '') # 无需手动设置Content-Length,urllib会自动根据字节流长度计算正确值 response = opener.open(request) LOGGER.info("Status code: %s", response.getcode()) LOGGER.info("Status message: %s", response.msg)
额外优化建议
当前代码中调用s3client.list_objects仅返回最多1000个对象,如果源桶对象超过1000个会出现复制不全的问题,建议替换为list_objects_v2结合分页逻辑处理全量对象。
内容的提问来源于stack exchange,提问作者Just curious
相关产品推荐
相关产品推荐

