文章目录
- 0.支付流程
- 1. 重点总结
- 2.后端代码
- 3.前端js
- 4.前端html
0.支付流程
1. 重点总结
1)用户进入“我的订单”页面,点击“去支付”;
触发后端js中的函数,发出ajsx异步请求,调用后端相应接口order_pay(order_id),目的是构建让用户跳转的支付连接地址,并推送给用户进行付款操作;因为请求方式是PUT,因此需要在参数中加入X-CSRFToken;
2)在后端进行逻辑处理,构建出跳转的支付链接地址pay_url(并指出用户完成支付后返回的地址return_url)。
支付链接地址经过js回调函数处理,将此pay_url返回给前端页面,此时自动打开手机支付宝app,用户对相应的订单进行支付操作,
支付完成后,跳转return_url相对应的前端页面paycomplete.html,如下图所示。
3)用户在支付完成后,需要修改数据库中订单的相关信息,比如说订单的状态status,以及支付宝的交易号trade_no,此时前端页面中的js向后端发送ajsx异步请求,向后端相应接口save_order_payment_result()发出逻辑处理。
js中alipayData = document.location.search.substr(1),切割URL中的参数信息,并以form格式将参数信息推送给后端接口,后端接收数据;
为安全起见,借助工具校验参数的合法性,确定参数是支付宝真实发出的;
最后修改数据库的订单状态信息。
此时,点击前文中支付成功界面中的“回到我的订单”,会发现订单状态已经从“去支付”变为“发表评论”。
2.后端代码
pay.py详细代码如下:
# coding:utf-8from . import api
from ihome.utils.commons import login_required
from ihome.models import Order
from flask import g, current_app, jsonify, request
from ihome.utils.response_code import RET
from alipay import AliPay
from ihome import constants, db
import os@api.route("/orders/<int:order_id>/payment", methods=["POST"])
@login_required
def order_pay(order_id):"""发起支付宝支付"""user_id = g.user_id# 判断订单状态try:order = Order.query.filter(Order.id == order_id, Order.user_id == user_id, Order.status == "WAIT_PAYMENT").first()except Exception as e:current_app.logger.error(e)return jsonify(errno=RET.DBERR, errmsg="数据库异常")if order is None:return jsonify(errno=RET.NODATA, errmsg="订单数据有误")# 创建支付宝sdk的工具对象alipay_client = AliPay(appid="2016081600258081",app_notify_url=None, # 默认回调urlapp_private_key_path=os.path.join(os.path.dirname(__file__), "keys/app_private_key.pem"), # 私钥alipay_public_key_path=os.path.join(os.path.dirname(__file__), "keys/alipay_public_key.pem"), # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,sign_type="RSA2", # RSA 或者 RSA2debug=True # 默认False)# 手机网站支付,需要跳转到https://openapi.alipaydev.com/gateway.do? + order_stringorder_string = alipay_client.api_alipay_trade_wap_pay(out_trade_no=order.id, # 订单编号total_amount=str(order.amount/100.0), # 总金额subject=u"爱家租房 %s" % order.id, # 订单标题return_url="http://127.0.0.1:5000/payComplete.html", # 返回的连接地址notify_url=None # 可选, 不填则使用默认notify url)# 构建让用户跳转的支付连接地址pay_url = constants.ALIPAY_URL_PREFIX + order_stringreturn jsonify(errno=RET.OK, errmsg="OK", data={"pay_url": pay_url})@api.route("/order/payment", methods=["PUT"])
def save_order_payment_result():"""保存订单支付结果"""alipay_dict = request.form.to_dict()# 对支付宝的数据进行分离 提取出支付宝的签名参数sign 和剩下的其他数据alipay_sign = alipay_dict.pop("sign")# 创建支付宝sdk的工具对象alipay_client = AliPay(appid="2016081600258081",app_notify_url=None, # 默认回调urlapp_private_key_path=os.path.join(os.path.dirname(__file__), "keys/app_private_key.pem"), # 私钥alipay_public_key_path=os.path.join(os.path.dirname(__file__), "keys/alipay_public_key.pem"),# 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,sign_type="RSA2", # RSA 或者 RSA2debug=True # 默认False)# 借助工具验证参数的合法性# 如果确定参数是支付宝的,返回True,否则返回falseresult = alipay_client.verify(alipay_dict, alipay_sign)if result:# 修改数据库的订单状态信息order_id = alipay_dict.get("out_trade_no")trade_no = alipay_dict.get("trade_no") # 支付宝的交易号try:Order.query.filter_by(id=order_id).update({"status": "WAIT_COMMENT", "trade_no": trade_no})db.session.commit()except Exception as e:current_app.logger.error(e)db.session.rollback()return jsonify(errno=RET.OK, errmsg="OK")
3.前端js
order.js中部分代码:
$.get("/api/v1.0/user/orders?role=custom", function(resp){if ("0" == resp.errno) {$(".orders-list").html(template("orders-list-tmpl", {orders:resp.data.orders}));$(".order-pay").on("click", function () {var orderId = $(this).parents("li").attr("order-id");$.ajax({url: "/api/v1.0/orders/" + orderId + "/payment",type: "post",dataType: "json",headers: {"X-CSRFToken": getCookie("csrf_token"),},success: function (resp) {if ("4101" == resp.errno) {location.href = "/login.html";} else if ("0" == resp.errno) {// 引导用户跳转到支付宝连接location.href = resp.data.pay_url;}}});});
4.前端html
order.html中部分代码:
<li order-id={{order.order_id}}><div class="order-title"><h3>订单编号:{{order.order_id}}</h3>{{ if "WAIT_COMMENT" == order.status }}<div class="fr order-operate"><button type="button" class="btn btn-success order-comment" data-toggle="modal" data-target="#comment-modal">发表评价</button></div>{{ else if "WAIT_PAYMENT" == order.status }}<div class="fr order-operate"><button type="button" class="btn btn-success order-pay">去支付</button></div>
paycomplete.html代码,此代码中有部分js代码,处理上文中的第三部分逻辑。
<!DOCTYPE html>
<html>
<head> <meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"><title>爱家-我的订单</title><link href="/static/plugins/bootstrap/css/bootstrap.min.css" rel="stylesheet"><link href="/static/plugins/font-awesome/css/font-awesome.min.css" rel="stylesheet"><link href="/static/css/reset.css" rel="stylesheet"><link href="/static/plugins/bootstrap-datepicker/css/bootstrap-datepicker.min.css" rel="stylesheet"><link href="/static/css/ihome/main.css" rel="stylesheet"><link href="/static/css/ihome/orders.css" rel="stylesheet">
</head>
<body><div class="container"><div class="top-bar"><div class="nav-bar"><h3 class="page-title">支付完成</h3><a class="nav-btn fl" href="/my.html"><span><i class="fa fa-angle-left fa-2x"></i></span></a></div></div><div class="orders-con"><p> 支付已完成 </p><a href="/orders.html">回到我的订单</a></div><div class="footer"><p><span><i class="fa fa-copyright"></i></span>爱家租房 享受家的温馨</p></div> </div><script src="/static/js/jquery.min.js"></script><script src="/static/plugins/bootstrap/js/bootstrap.min.js"></script><script src="/static/plugins/bootstrap-datepicker/js/bootstrap-datepicker.min.js"></script><script src="/static/plugins/bootstrap-datepicker/locales/bootstrap-datepicker.zh-CN.min.js"></script><script src="/static/js/template.js"></script><script type="text/javascript">function getCookie(name) {var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");return r ? r[1] : undefined;}var alipayData = document.location.search.substr(1);$.ajax({url: "/api/v1.0/order/payment",type: "put",data: alipayData,headers: {"X-CSRFToken": getCookie("csrf_token")}})</script>
</body>
</html>
返回顶部