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的实现:
- 直接使用
request.session['order_id']获取会话值,若session中无该键会直接抛出KeyError,后续的if order_id is None判断根本无法执行。 - 回调时可能存在session丢失的情况(比如跨域、会话过期),仅依赖session获取order_id风险较高。
- 验证成功后未调用
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
相关产品推荐
相关产品推荐

