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

Django电商站点支付验证出现KeyError: 'order_id'问题求助

Django电商站点支付回调出现KeyError: 'order_id'的解决方案

问题概述

电商站点点击支付确认订单后,/verify/路径触发500内部服务器错误,报错KeyError: 'order_id',核心原因是会话(session)中未正确存储或获取order_id。

报错信息

Internal Server Error: /verify/
Traceback (most recent call last):
  File "C:\Users\QK\Desktop\MAworkshop\.venv\Lib\site-packages\django\core\handlers\exception.py", line 55, in inner
    response = get_response(request)
               ^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\QK\Desktop\MAworkshop\.venv\Lib\site-packages\django\core\handlers\base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\QK\Desktop\MAworkshop\.venv\Lib\site-packages\django\views\generic\base.py", line 104, in view
    return self.dispatch(request, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\QK\Desktop\MAworkshop\.venv\Lib\site-packages\django\views\generic\base.py", line 143, in dispatch
    return handler(request, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\QK\Desktop\MAworkshop\cart\views.py", line 124, in get
    order_id = request.session['order_id']
               ~~~~~~~~~~~~~~~^^^^^^^^^^^^
  File "C:\Users\QK\Desktop\MAworkshop\.venv\Lib\site-packages\django\contrib\sessions\backends\base.py", line 53, in __getitem__
    return self._session[key]
           ~~~~~~~~~~~~~^^^^^
KeyError: 'order_id'
[26/Jul/2024 09:38:14] "GET /verify/?Authority=000000000000000000000000000001476833&Status=OK HTTP/1.1" 500 83027
Not Found: /favicon.ico
[26/Jul/2024 09:38:14] "GET /favicon.ico HTTP/1.1" 404 5053

代码问题分析

从提供的views.py代码看,核心问题出在VerifyView的实现:

  1. 直接使用request.session['order_id']获取会话值,若session中无该键会直接抛出KeyError,后续的if order_id is None判断根本无法执行。
  2. 回调时可能存在session丢失的情况(比如跨域、会话过期),仅依赖session获取order_id风险较高。
  3. 验证成功后未调用order.save()保存订单状态,且返回值不符合Django视图要求(直接返回字典而非HttpResponse子类)。

修复方案

1. 安全获取order_id,避免KeyError

修改VerifyView中获取order_id的逻辑,使用.get()方法安全取值,同时增加备用获取方式(从GET参数中读取):

class VerifyView(View):
    def get(self, request):
        # 优先从session获取,失败则尝试从GET参数读取
        order_id = request.session.get('order_id') or request.GET.get('order_id')
        
        if not order_id:
            return HttpResponse("订单ID不存在", status=400)
        
        try:
            order = Order.objects.get(id=order_id)
        except Order.DoesNotExist:
            return HttpResponse("订单不存在", status=404)
        
        # 修正Authority参数的获取方式(原代码用request.get错误)
        authority = request.GET.get("Authority")
        if not authority:
            return HttpResponse("缺少支付授权码", status=400)
        
        data = {
            "MerchantID": settings.MERCHANT,
            "Amount": order.total_price,
            "Authority": authority,
        }
        data = json.dumps(data)
        headers = {'content-type': 'application/json', 'content-length': str(len(data))}
        
        try:
            response = requests.post(ZP_API_VERIFY, data=data, headers=headers, timeout=10)
        except requests.exceptions.Timeout:
            return JsonResponse({'status': False, 'code': 'timeout'})
        except requests.exceptions.ConnectionError:
            return JsonResponse({'status': False, 'code': 'connection error'})
        
        if response.status_code == 200:
            response_data = response.json()
            if response_data['Status'] == 100:
                order.is_paid = True
                order.save()  # 保存订单支付状态
                return JsonResponse({'status': True, 'RefID': response_data['RefID']})
            else:
                return JsonResponse({'status': False, 'code': str(response_data['Status'])})
        return JsonResponse(response.json(), status=response.status_code)

2. 强化session存储可靠性

在SendRequestView中设置session后,手动调用request.session.save()确保会话数据被持久化,同时动态生成回调URL附加order_id作为备用:

class SendRequestView(View):
    def post(self, request, pk):
        order = get_object_or_404(Order, id=pk, user=request.user)
        address = get_object_or_404(Address, id=request.POST.get('address'))
        order.address = f"{address.address} - {address.phone}"
        order.save()
        
        # 存储order_id到session并手动保存
        request.session['order_id'] = str(order.id)
        request.session.save()
        
        # 动态生成回调URL,附加order_id作为备用
        callback_url = f'http://127.0.0.1:8000/verify/?order_id={order.id}'
        
        data = {
            "MerchantID": settings.MERCHANT,
            "Amount": order.total_price,
            "Description": description,
            "Phone": request.user.phone,
            "CallbackURL": callback_url,
        }
        # 后续代码保持不变...

3. 确保会话一致性

  • 本地测试时,回调URL的域名需和站点域名完全一致(均为127.0.0.1:8000),避免跨域导致session丢失。
  • 生产环境中,确保使用HTTPS并配置正确的SESSION_COOKIE_DOMAIN。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 11:55:54