AWS Lambda对接Watson Webhook:Postman调用报交易类型无效
AWS Lambda函数Postman调用报错:无效交易类型问题排查与修复
问题描述
我开发了一款基于Python的AWS Lambda函数,用于存储银行用户账户信息及实现用户间、用户与子用户间的交易功能,计划通过Webhook集成至IBM Watson Assistant。该函数在AWS云环境内测试运行正常,但使用Postman调用时,即便传入如下正确参数:
{
"input_json": {
"transaction_type": "self_transfer",
"user_name": "Vivek kaushal",
"amount": 100
}
}
仍返回错误:{"error": "Invalid transaction type. Please provide a valid 'transaction_type'."}
对应的Lambda代码如下:
import json import boto3 s3 = boto3.resource(service_name='s3', region_name='ap-south-1', aws_access_key_id="*****************", aws_secret_access_key="******************************") bucket_name = 'bank.users' file_key = 'user_details.json' def get_file_object(): try: obj = s3.Object(bucket_name, file_key) file_content = obj.get()['Body'].read().decode('utf-8') file_obj = json.loads(file_content) return file_obj except Exception as e: print(f"Error loading file from S3: {str(e)}") return None def save_file_object(file_obj): try: obj = s3.Object(bucket_name, file_key) obj.put(Body=json.dumps(file_obj)) except Exception as e: print(f"Error saving file to S3: {str(e)}") def transfer_money_within_user(args): # Load the data from the JSON file file_obj = get_file_object() if file_obj is None: return { 'error': "Failed to load user details from S3." } user_name = args.get('user_name') sub_user_name = args.get('sub_user_name') amount = args.get('amount') # Search for the user and sub user for user in file_obj['users']: if user['user_name'] == user_name: sub_users = user.get('sub_users', []) # Search for the sub user based on the name for sub_user in sub_users: if sub_user['sub_user_name'] == sub_user_name: user_balance = user['bank_details']['balance'] # Check if the user has sufficient balance if user_balance >= amount: # Update the sub user balance sub_user['bank_details']['balance'] += amount # Update the user balance user['bank_details']['balance'] -= amount # Save the updated data to S3 save_file_object(file_obj) # Return the updated data as a JSON response return { 'message': f"Money transferred successfully from user '{user_name}' to sub user '{sub_user_name}'.", 'remaining_balance': user['bank_details']['balance'] } else: return { 'error': f"Insufficient balance in user '{user_name}' to transfer the amount.", 'current_balance': user['bank_details']['balance'] } # If sub user not found, ask if the user wants to add a new sub user return { 'error': "Sub user not found. Do you want to add a new sub user?", 'add_new_sub_user': True } # If user not found, return an error message return { 'error': f"No user found with the name '{user_name}'." } def transfer_money_between_users(args): # Load the data from the JSON file file_obj = get_file_object() if file_obj is None: return { 'error': "Failed to load user details from S3." } sender_user_name = args.get('sender_user_name') recipient_user_name = args.get('recipient_user_name') amount = args.get('amount') # Search for the sender user and recipient user sender_user = None recipient_user = None for user in file_obj['users']: if user['user_name'] == sender_user_name: sender_user = user elif user['user_name'] == recipient_user_name: recipient_user = user # Check if both sender user and recipient user are found if sender_user and recipient_user: sender_user_balance = sender_user['bank_details']['balance'] # Check if the sender user has sufficient balance if sender_user_balance >= amount: # Update the sender user balance sender_user['bank_details']['balance'] -= amount # Update the recipient user balance recipient_user['bank_details']['balance'] += amount # Save the updated data to S3 save_file_object(file_obj) # Return the updated data as a JSON response return { 'message': f"Money transferred successfully from user '{sender_user_name}' to user '{recipient_user_name}'.", 'remaining_balance': sender_user['bank_details']['balance'] } else: # If sender user does not have sufficient balance, return an error message return { 'error': f"Insufficient balance in user '{sender_user_name}' to transfer the amount.", 'current_balance': sender_user['bank_details']['balance'] } else: # If either sender user or recipient user is not found, return an error message error_msg = "" if not sender_user: error_msg += f"No sender user found with the name '{sender_user_name}'.\n" if not recipient_user: error_msg += f"No recipient user found with the name '{recipient_user_name}'.\n" return { 'error': error_msg.strip() } def transfer_money_to_self(args): # Load the data from the JSON file file_obj = get_file_object() if file_obj is None: return { 'error': "Failed to load user details from S3." } user_name = args.get('user_name') amount = args.get('amount') # Search for the user for user in file_obj['users']: if user['user_name'] == user_name: user_balance = user['bank_details']['balance'] # Check if the user has sufficient balance if user_balance >= amount: # Update the user balance user['bank_details']['balance'] -= amount # Save the updated data to S3 save_file_object(file_obj) # Return the updated data as a JSON response return { 'message': f"Money transferred successfully from user '{user_name}' to itself.", 'remaining_balance': user['bank_details']['balance'] } else: return { 'error': f"Insufficient balance in user '{user_name}' to transfer the amount.", 'current_balance': user['bank_details']['balance'] } # If user not found, return an error message return { 'error': f"No user found with the name '{user_name}'." } def lambda_handler(event, context): input_json = event.get('input_json', {}) transaction_type = str(input_json.get('transaction_type')) if transaction_type == 'user': sender_user_name = str(input_json.get('sender_user_name')) recipient_user_name = str(input_json.get('recipient_user_name')) amount = float(input_json.get('amount')) # Invoke the transfer_money_between_users function with the parameters result = transfer_money_between_users({ 'sender_user_name': sender_user_name, 'recipient_user_name': recipient_user_name, 'amount': amount }) elif transaction_type == 'sub_user': user_name = str(input_json.get('user_name')) sub_user_name = str(input_json.get('sub_user_name')) amount = float(input_json.get('amount')) # Invoke the transfer_money_within_user function with the parameters result = transfer_money_within_user({ 'user_name': user_name, 'sub_user_name': sub_user_name, 'amount': amount }) elif transaction_type == 'add_sub_user': user_name = str(input_json.get('user_name')) sub_user_name = str(input_json.get('sub_user_name')) balance = float(input_json.get('balance', 0)) account_number = str(input_json.get('account_number')) mobile_number = str(input_json.get('mobile_number')) bank = str(input_json.get('bank')) ifsc_code = str(input_json.get('ifsc_code')) # Load the data from the JSON file file_obj = get_file_object() if file_obj is None: return { 'statusCode': 500, 'body': json.dumps({ 'error': "Failed to load user details from S3." }) } # Search for the user based on the name for user in file_obj['users']: if user['user_name'] == user_name: sub_users = user.get('sub_users', []) # Check if the sub user already exists if any(sub_user['sub_user_name'] == sub_user_name for sub_user in sub_users): return { 'statusCode': 400, 'body': json.dumps({ 'error': f"Sub user '{sub_user_name}' already exists for user '{user_name}'." }) } else: # Add the new sub user with bank details new_sub_user = { 'sub_user_name': sub_user_name, 'bank_details': { 'balance': balance, 'account_number': account_number, 'mobile_number': mobile_number, 'bank': bank, 'ifsc_code': ifsc_code } } sub_users.append(new_sub_user) # Save the updated data to S3 save_file_object(file_obj) return { 'statusCode': 200, 'body': json.dumps({ 'message': f"New sub user '{sub_user_name}' added for user '{user_name}' with balance {balance}." }) } # If user not found, return an error message return { 'statusCode': 404, 'body': json.dumps({ 'error': f"No user found with the name '{user_name}'." }) } elif transaction_type == 'self_transfer': user_name = str(input_json.get('user_name')) amount = float(input_json.get('amount')) # Invoke the transfer_money_to_self function with the parameters result = transfer_money_to_self({ 'user_name': user_name, 'amount': amount }) else: return { 'statusCode': 400, 'body': json.dumps({ 'error': "Invalid transaction type. Please provide a valid 'transaction_type'." }) } return { 'statusCode': 200, 'body': json.dumps(result) }
问题根源
AWS控制台测试Lambda时,event参数直接包含input_json顶级字段;但通过Postman或外部Webhook调用Lambda URL时,请求的JSON体被Lambda封装在event['body']字段中,而非直接作为event的顶级属性。
代码中input_json = event.get('input_json', {})在Postman调用时会获取到空字典,导致transaction_type被转为空字符串,最终触发无效交易类型的错误分支。
修复方案
修改lambda_handler函数开头逻辑,兼容两种请求结构:
def lambda_handler(event, context): # 处理Postman等外部调用:解析body中的JSON内容 if 'body' in event: try: event = json.loads(event['body']) except json.JSONDecodeError: return { 'statusCode': 400, 'body': json.dumps({ 'error': "请求体JSON格式无效" }) } input_json = event.get('input_json', {}) transaction_type = str(input_json.get('transaction_type')) # 后续原有逻辑保持不变...
额外优化建议
- 移除代码中硬编码的AWS密钥,改用Lambda执行角色的权限访问S3,提升安全性。
- 增加
transaction_type为空的判断,返回更明确的错误提示。 - 确认
transfer_money_to_self函数的业务合理性,通常"转账给自己"属于冗余操作,可根据需求调整逻辑。
内容的提问来源于stack exchange,提问作者Shaik Saad Abdul Tawwab
相关产品推荐
相关产品推荐

