正常情况下我们只需要一个post回调给支付宝用(不需要登录认证,因为支付宝验证签名后===>校验成功,我们才会进行改订单状态)
同时这里咱们写了一个get回调,用于给前端做数据校验,做双重验证,更加稳妥
如果我们的notify_url是本地调试,外网无法访问,就会使支付宝无法回调而失败,所以我们可以利用内网穿透:
内网穿透:https://zhuanlan.zhihu.com/p/370483324
支付成功回调接口
order/views.py
方案一:
# 后端支付跳转接口 这里不需要大量用到数据库交互 所以选择用APIView更方便
class SuccessView(APIView):
# 支付宝get回调前端页面 前端页面get请求后端校验数据
def get(self,request,*args,**kwargs):
# 从请求参数中获取订单号
out_trade_no = request.query_params.get('out_trade_no')
order_obj = models.Order.objects.filter(out_trade_no=out_trade_no).first()
# 判断订单支付状态 返回True/False 前端自行处理
if order_obj.order_status == 1:
return Response(True)
else:
return Response(False)
# 支付宝回调接口
def post(self,request,*args,**kwargs):
from luffyapi.libs.alipay_zf import alipay
from luffyapi.utils.logger import log
# 继承APIView post请求来的时候 获取前端传过来的数据
# 这里是QueryDict对象 不允许通过pop删除数据 所以我们转成dict类型
data = request.data.dict()
print(type(data))
# 获取订单号 key参考alipay的API参数
out_trade_no = data.get('out_trade_no',None)
# 获取支付时间 key参考alipay的API参数
gmt_payment = data.get('gmt_payment',None)
# 获取签名
signature = data.pop("sign")
# 验证签名 只有签名正确 才能修改订单状态 防止有人恶意发送post请求给我们
success = alipay.verify(data, signature)
# 判断订单状态 交易完成/支付成功
if success and data["trade_status"] in ("TRADE_SUCCESS", "TRADE_FINISHED"):
# 更新订单支付状态以及付款时间
models.Order.objects.filter(out_trade_no=out_trade_no
).update(order_status=1,pay_time=gmt_payment)
# 记录日志
log.info('%s订单支付成功'%out_trade_no)
return Response('success') # 这里固定返回值 否则支付宝会8次异步回调
else:
log.info('%s订单支付异常'%out_trade_no)
return Response('error')
方案二:
from rest_framework.views import APIView
from .models import Order
class PaySuccessView(APIView):
def get(self,request): # 自己用的
try:
out_trade_no=request.query_params.get('out_trade_no')
# 根据订单号,查订单的状态
Order.objects.get(out_trade_no=out_trade_no,order_status=1)
except Exception as e:
raise e
return APIResponse()
# 给支付宝用---》回调回来数据格式
def post(self,request):
# django :requset.POST request.GET --->QueryDict的对象--》不允许删除数据
try:
result_data = request.data.dict() # request.data 是post的数据,复制了一份数据
out_trade_no = result_data.get('out_trade_no') # 订单号
signature = result_data.pop('sign') # 签名
from libs import apay
# 验证签名,只有这个正确,才能修改订单状态--》防止恶意发送post请求给我们
result = apay.pay.verify(result_data, signature)
if result and result_data["trade_status"] in ("TRADE_SUCCESS", "TRADE_FINISHED"):
# 完成订单修改:订单状态、流水号、支付时间
models.Order.objects.filter(out_trade_no=out_trade_no).update(order_status=1)
# 完成日志记录
logger.warning('%s订单支付成功' % out_trade_no)
return Response('success') # 固定的
else:
logger.error('%s订单支付失败' % out_trade_no)
except:
pass
return Response('failed')
View Code
order/urls.py
from django.urls import path, re_path, include
from . import views
from rest_framework.routers import SimpleRouter
router = SimpleRouter()
router.register('pay',views.PayView,'pay')
urlpatterns = [
path('', include(router.urls)),
path('success/',views.SuccessView.as_view(),'success')
]
settings/dev.py
LUFFY_URL = "http://127.0.0.1:8080" # 前台基URL
BASE_URL = "http://127.0.0.1:8000" # 后台基URL
RETURN_URL= LUFFY_URL + "/pay/success" # 支付宝get回调,前台地址 尾部没有/
NOTIFY_URL= BASE_URL + "/order/success/" # 支付宝post异步回调,后台地址