React Fetch无法向Cloud Run的Flask API传递POST数据求助
问题解决:Flask API接收React POST数据时的AttributeError错误
问题说明
部署在Google Cloud Run的Flask API,在接收React端通过fetch发送的POST JSON数据并转发至第三方支付平台时,触发以下错误:
File "/app/app.py", line 39, in index total = data.get("orderSummary").get("total") AttributeError: 'NoneType' object has no attribute 'get'
错误原因
React端直接将orderSummary对象序列化为请求体发送(JSON结构为{"total": xxx, "s1": xxx, ...}),但Flask端错误地尝试从请求数据中获取嵌套的orderSummary字段,导致data.get("orderSummary")返回None,调用get("total")时触发AttributeError。
修复方案
提供两种可行修复方式,可根据需求选择:
方案一:修改Flask端代码(推荐,无需改动前端)
直接从请求的JSON根节点获取字段,同时添加基础错误校验避免后续异常:
def index(path): # GET request if request.method == 'GET': return { "loaded": True, "val": "Flask Api running in the cloud" } # POST request if request.method == 'POST': data = request.get_json(force=True) # 先打印接收到的数据,方便调试 logging.info(f"Received data: {data}") # 直接从data根节点获取字段,添加非空校验 total = data.get("total") r = data.get("s1") ac = data.get("s2") fname = data.get("fname") lname = data.get("lname") memo = data.get("memo") city = data.get("city") state = data.get("state") zipcode = data.get("zipcode") addy = data.get("addy") email = data.get("email") items = data.get("items") phone_number = data.get("phone") # 校验关键字段是否存在 required_fields = ["total", "s1", "s2", "fname", "lname", "email"] missing_fields = [f for f in required_fields if not data.get(f)] if missing_fields: return jsonify({"error": f"Missing required fields: {', '.join(missing_fields)}"}), 400 logging.info(total, r, ac, fname, lname, memo, city, state, zipcode, addy, email, items, phone_number) # 后续第三方请求、邮件发送逻辑保持不变 app.config.from_pyfile('./settings.py') load_dotenv('.env') url = 'https://sandbox.seamlesschex.com/v1/check/create' payload = json.dumps({ "number": random.randint(1,999999), "email": email, "authorization_date": date.today(), "label": "Thank you from Chubby's", "address": addy, "city": city, "state": state, "zip": zipcode, "phone": phone_number, "bank_account": ac, "bank_routing": r, "name": fname + " " + lname, "memo": memo, "amount": total, }, separators=(',', ':'), default=str) headers = { 'Content-Type': 'application/json', 'Authorization': app.config.get("SEAMLESS_SANDBOX_KEY") } response = requests.request('POST', url, headers = headers, data = payload, allow_redirects=False, timeout=1000000000) data = response.json() checkDATA = data.get('check') # 使用get避免KeyError if checkDATA: # 导入语句建议移至文件顶部,此处仅为示例保留 from flask import jsonify from flask_mail import Mail, Message mail_settings = { "MAIL_SERVER": app.config.get("EMAIL_SERVER"), "MAIL_PORT": 465, "MAIL_USE_TLS": False, "MAIL_USE_SSL": True, "MAIL_USERNAME": app.config.get("EMAIL_ACCT"), "MAIL_PASSWORD": app.config.get("EMAIL_PWD") } app.config.update(mail_settings) mail = Mail(app) with app.app_context(): msgToCustomer = Message(subject="Successful Order Initiation With Chubbys Seed Supply Co.", sender=app.config.get("EMAIL_ACCT"), recipients=[email], body="The Biggest Chubbys' thank you is sent to you today. We recived your order today and are dilligently processing your order and getting it all packaged up nice and neat and safe. Be on the lookout in your inbox for an email with the traking number. We'll send you an email with the tracking number once the Post Office has your package and it's on the way :). Thank you and have a great day. ") mail.send(msgToCustomer) msgToChubbys = Message(subject="NEW_ORDER_NEEDS TO BE FULLFILLED", sender=app.config.get("EMAIL_ACCT"), recipients=[app.config.get("EMAIL_ACCTT")], body=f"New order for {fname} {lname}. The order total is {total} and the order consists of the following items {items}. Send to {addy} {city} {state} {zipcode}. Send tracking number to {email} ") mail.send(msgToChubbys) return jsonify(checkDATA) # 使用jsonify替代json.dumps,更符合Flask规范
方案二:修改React端代码
将orderSummary包装在包含orderSummary键的对象中发送,匹配Flask端期望的结构:
// 原代码:options.body = JSON.stringify(orderSummary) // 修改为: options.body = JSON.stringify({ orderSummary })
额外优化建议
- Flask端建议将所有导入语句(如
from flask import Flask, jsonify、import requests等)移至文件顶部,避免在函数内部重复导入。 - 第三方请求部分可添加异常捕获,处理请求超时、网络错误等情况。
- React端可添加fetch的错误捕获逻辑,处理HTTP状态码非200的情况:
fetch(process.env.REACT_APP_SEAMLESS_URL, options) .then(response => { if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`); return response.body; }) // 后续逻辑保持不变 .catch(error => console.error('Fetch error:', error));
内容的提问来源于stack exchange,提问作者Robert Zobrist
相关产品推荐
相关产品推荐

