无需Postman:如何用AWS Signature认证调用Lambda函数并解决签名异常?
一、HTTP请求方法选择
用POST请求,因为需要传递请求体(包含text参数),PUT多用于资源更新,POST更适合提交数据触发Lambda执行。
二、Cloudshell签名不匹配问题解决
改用AWS签名工具生成请求
Postman导出的cURL可能包含临时凭证(如用了IAM临时会话),Cloudshell中环境凭证如果不匹配就会报错。直接用awscurl生成带正确签名的请求更可靠:- 安装awscurl:
pip install awscurl - 执行请求(替换占位符为你的实际信息):
awscurl --service lambda --region us-east-1 -X POST -H "Content-Type: application/json" -d '{"text": "Test text to speech"}' https://<API_GATEWAY_ID>.execute-api.us-east-1.amazonaws.com/<STAGE>/<FUNCTION_NAME>
- 安装awscurl:
校验凭证与签名版本
确认Cloudshell中的AWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEY、AWS_SESSION_TOKEN(临时凭证时)正确,执行echo $AWS_ACCESS_KEY_ID查看。Lambda API要求使用Signature Version 4,awscurl默认会用该版本,避免签名格式错误。
三、Make.com请求体识别问题解决
配置原始JSON请求体
Make.com的Lambda模块默认可能将请求体解析为键值对,而你的代码期望event['body']是JSON字符串。在Make中设置请求体为原始JSON格式,粘贴{"text": "Test text to speech"},同时指定Content-Type为application/json。兼容多格式输入
修改Lambda代码,同时支持API Gateway的body字符串格式和Make.com直接传递的JSON对象:import json import boto3 import uuid def lambda_handler(event, context): polly = boto3.client('polly') s3 = boto3.client('s3') # 兼容两种输入格式 if isinstance(event, dict) and 'text' in event: text = event['text'] elif 'body' in event: try: body = json.loads(event['body']) if 'text' not in body: return { 'statusCode': 400, 'body': json.dumps('Error: text field is required') } text = body['text'] except json.JSONDecodeError: return { 'statusCode': 400, 'body': json.dumps('Error: Invalid JSON in request body') } else: return { 'statusCode': 400, 'body': json.dumps('Error: Request body missing or text field not found') } bucket_name = 'pollytts--use1-az6--x-s3' # 生成唯一文件名避免覆盖 object_key = f'converted-speech-{uuid.uuid4()}.mp3' try: response = polly.synthesize_speech( Text=text, OutputFormat='mp3', VoiceId='Joanna' ) audio_stream = response['AudioStream'].read() s3.put_object( Bucket=bucket_name, Key=object_key, Body=audio_stream, ContentType='audio/mpeg' ) # 生成预签名URL(私有桶也能访问) file_url = s3.generate_presigned_url('get_object', Params={'Bucket': bucket_name, 'Key': object_key}, ExpiresIn=3600) return { 'statusCode': 200, 'body': json.dumps({'url': file_url}) } except Exception as e: return { 'statusCode': 500, 'body': json.dumps(f'Error: {str(e)}') }
四、优化实时性与可靠性
避免文件覆盖
用UUID生成唯一的S3对象键,防止多个请求同时执行时覆盖MP3文件,确保返回的URL对应最新转换的内容。使用预签名URL
如果S3桶不是公开可读的,直接生成的公共URL会无法访问。预签名URL可设置有效期(如1小时),无需公开桶即可让用户访问文件,更安全。添加调试日志
在Lambda函数开头添加日志打印,方便排查输入问题:print("Received event:", json.dumps(event))可在CloudWatch Logs中查看完整的event内容,确认请求体是否正确传递。
内容的提问来源于stack exchange,提问作者Talib Kareem

