You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flask路由间Session值无法持久化问题排查求助

问题描述

开发Flask应用时,在payment_callback路由中设置了session['response_status'],但在payment_result路由中读取该值时始终为None。日志显示payment_callback中session已正确设置,但跳转后无法获取。

代码片段

@app.route('/payment/callback', methods=['POST'])
def payment_callback():    
    global processed_transactions

    try:    
        data = get_request_data()    
        logger.info(f"Received data: {data}")    
        response_status = decode_if_bytes(data.get('payment_result', {}).get('response_status'))    
        if response_status:        
            session['response_status'] = response_status        
            logger.info(f"Callback session data: {dict(session)}")    
        else:        
            logger.warning("Response status not found in the received data.")    
        return redirect(url_for('payment_result'))

    except Exception as e:    
        logger.error(f"Error querying transaction: {e}")    
        flash('Error querying transaction', 'danger')    
        return redirect(url_for('index')) 

@app.route('/payment/return', methods=['GET', 'POST'])
def payment_return():    
    time.sleep(3)    
    logger.info('------return--------')    
    return redirect(url_for('payment_result'))

@app.route('/payment/result')
def payment_result():    
    print('I want to get response status')    
    response_status = session.get('response_status')    
    print(response_status)  # Output is NONE----------------- here is the problem    
    return render_template('Payment_Result.html')

日志输出

INFO:main:Received data: {'tran_ref': 'TST2417201883637', 'merchant_id': 78035, 'profile_id': 137790, 'cart_id': 'card_123', 'cart_description': 'Sample Payment', 'cart_currency': 'EGP', 'cart_amount': '10.00', 'tran_currency': 'EGP', 'tran_total': '10.00', 'tran_type': 'Sale', 'tran_class': 'ECom', 'customer_details': {'name': 'shady Henawy wardy', 'email': 'shadywardy@gmail.com', 'street1': 'Cairo', 'city': 'Cairo', 'state': 'GZ', 'country': 'EG', 'zip': '11637', 'ip': '197.49.115.176'}, 'payment_result': {'response_status': 'A', 'response_code': 'G01271', 'response_message': 'Authorised', 'acquirer_ref': 'TRAN0001.66745A17.0003D57B', 'cvv_result': ' ', 'avs_result': ' ', 'transaction_time': '2024-06-20T16:34:31Z'}, 'payment_info': {'payment_method': 'Visa', 'card_type': 'Credit', 'card_scheme': 'Visa', 'payment_description': '4000 00## #### 0002', 'expiryMonth': 6, 'expiryYear': 2029}, 'ipn_trace': 'IPNS0001.66745A17.00005B19'}

INFO:main:Callback session data: {'response_status': 'A'}

INFO:werkzeug:127.0.0.1 - - [20/Jun/2024 19:34:38] "POST /payment/callback HTTP/1.1" 302 -

INFO:main:------return--------

INFO:werkzeug:127.0.0.1 - - [20/Jun/2024 19:34:41] "GET /payment/return HTTP/1.1" 302 -

INFO:werkzeug:127.0.0.1 - - [20/Jun/2024 19:34:41] "GET /payment/result HTTP/1.1" 200 -

I want to get response status

None

核心原因

问题出在会话隔离:payment_callback是支付网关服务器发起的POST请求,这个请求的session属于网关的会话,和用户浏览器的会话完全无关。你在callback里设置的session是网关请求的session,而用户访问payment_result时用的是自己浏览器的session,自然读不到之前设置的值。

修复方案

不能用session传递跨会话的数据,改用以下两种常用方案:

方案1:用交易标识存储状态到数据库/缓存

  1. 在payment_callback中,将response_status和交易ID(比如tran_ref)一起存入数据库或Redis缓存
  2. 在payment_result中,通过用户会话里的交易ID(发起支付时应该已存在用户session)去查询状态

示例代码:

# 假设用SQLAlchemy存储交易状态
from models import Transaction  # 自定义的交易模型

@app.route('/payment/callback', methods=['POST'])
def payment_callback():    
    global processed_transactions

    try:    
        data = get_request_data()    
        logger.info(f"Received data: {data}")
        tran_ref = data.get('tran_ref')
        response_status = decode_if_bytes(data.get('payment_result', {}).get('response_status'))    
        
        if response_status and tran_ref:        
            # 存入数据库
            transaction = Transaction.query.filter_by(tran_ref=tran_ref).first()
            if transaction:
                transaction.response_status = response_status
                db.session.commit()
            logger.info(f"Updated transaction {tran_ref} status to {response_status}")    
        else:        
            logger.warning("Response status or tran_ref not found in the received data.")    
        return redirect(url_for('payment_result'))

    except Exception as e:    
        logger.error(f"Error querying transaction: {e}")    
        flash('Error querying transaction', 'danger')    
        return redirect(url_for('index')) 

@app.route('/payment/result')
def payment_result():    
    print('I want to get response status')
    # 从用户session获取之前存储的交易ID
    tran_ref = session.get('current_tran_ref')
    response_status = None
    if tran_ref:
        transaction = Transaction.query.filter_by(tran_ref=tran_ref).first()
        if transaction:
            response_status = transaction.response_status
    print(response_status)    
    return render_template('Payment_Result.html', response_status=response_status)

方案2:通过redirect传递参数(适合非敏感状态)

如果response_status不是敏感信息,可以在payment_callback重定向时将其作为参数传递,然后payment_result从请求参数中获取:

@app.route('/payment/callback', methods=['POST'])
def payment_callback():    
    global processed_transactions

    try:    
        data = get_request_data()    
        logger.info(f"Received data: {data}")    
        response_status = decode_if_bytes(data.get('payment_result', {}).get('response_status'))    
        if response_status:        
            # 重定向时携带参数
            return redirect(url_for('payment_result', status=response_status))    
        else:        
            logger.warning("Response status not found in the received data.")    
            return redirect(url_for('payment_result'))

    except Exception as e:    
        logger.error(f"Error querying transaction: {e}")    
        flash('Error querying transaction', 'danger')    
        return redirect(url_for('index')) 

@app.route('/payment/result')
def payment_result():    
    print('I want to get response status')
    # 从请求参数获取状态
    response_status = request.args.get('status')
    print(response_status)    
    return render_template('Payment_Result.html', response_status=response_status)

注意:方案2的参数会暴露在URL中,若状态包含敏感信息不建议使用,优先选方案1。

内容的提问来源于stack exchange,提问作者shady

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 04:42:03