zoukankan      html  css  js  c++  java
  • 09 调用支付宝接口

    安装

    pip install python-alipay-sdk
    

      

    生成密钥文件

    openssl
    

      

    生成私钥

    genrsa -out app_private_key.pem 2048
    

      

    ctr + d退出

    ls 查看生成的私钥文件

    cat app_private_key.pem

    生成公钥

    rsa -in app_private_key.pem -pubout -out app_public_key.pem
    

      

    可以在另一个终端ls查看

    私钥保存在程序中,公钥放到支付宝中

    cat app_public_key.pem
    

    把上面的公钥放到支付宝的沙箱应用的查看公钥中,除去上下的修饰

    MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtL8j5quexGUn5dGTdO76
    vx+yfkpOQFkTymk1FALj0FSWucrM7u8+8O5DJtbRI+Skt9tGRNU/ZjG6IlQUBzmM
    xIB3b0I3I5GCg2ZaFWmqblzcqo3RZ9aC+kOX9h3o/xeaq5aemwRsPxezJoFmF38f
    6YwR8YIWWnqsFw93MWahbeSt02qnZPwKnq41zUSV/iPogUubLud2D7Dg+cgREfm8
    pflbTL4utt41PU7O+tbGUet9fQKpliTESs7Gda/IMZf9KtbBKQCjxiVKiLHcMQje
    0FcaaYWtyEebE02E4qIqnHRUklKExj1/mQfXQsum0wO6+EQPuN9VSQUaAMSfqQiq

    把家目录中的私钥放到程序中的orders应用中

    把支付宝的公钥复制到程序中

    在orders应用中新建一个文件alipay_public_key.pem

    将公钥的内容复制保存到一个文本文件中(alipay_pubilc_key.pem),注意需要在文本的首尾添加标记位(-----BEGIN PUBLIC KEY-----和-----END PUBLIC KEY-----) ,形如:

    -----BEGIN PUBLIC KEY-----
    MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzkXJrjPbdu2DdCygEChuLzuBq0Hhvp2SOoe4LzPR0LyKcQF3TM/5O/K5YlNuspeZgMqm+mNLmpp6ahfo6RrMSrnZ9f5jN81mz7ZAIe7PAG0Fj1lTzkBNLu2Ab2NVgkHT9wf/Qgug+Vef4bSVyVdED9cCxsZq76BdSKHKoSufts1YK8QzEg7oX4f/FcRyo1afuqXl2HV+LSTstw0nLq9VkaOawP5bewTg4L7yIIjsb+RLDO7mwTOe3HoGxmWOTU+EIJk2AWqaQWAIGpRQrQZ54T/B8K0wcuGsTt6Ru5Z2XcGvZ6Mk1drQsZ6u1AuOPIvlR7FM8+azGbQmADLevseYOwIDAQAB
    -----END PUBLIC KEY-----
    


    用户通过支付宝完成提交订单

     支付宝接口文档   https://github.com/fzlee/alipay/blob/master/README.zh-hans.md

    前端的页面如下所示:

     

     因为后端要向支付宝发送请求,需要向支付宝传递的参数有

      订单的编号

      订单的金额

    所以前端需要向后端传送这两个参数,因为后端可以根据订单的编号找到订单的信息表,所以订单的金额可以不传,只需传送订单的标号即可,

    后端会给前端返回一个支付宝的页面地址,可以引导用户在这个页面付款

     前端的js代码:

    必须是待支付的状态,才会发送请求

        <script type="text/javascript">
            $('.oper_btn').click(function() {
                var order_id = $(this).attr("order_id");
                var order_status = $(this).attr("order_status");
                order_status = parseInt(order_status);
                if (1 == order_status) {
                    // 表示待支付
                    var req_data ={
                        order_id:order_id,
                        csrfmiddlewaretoken: "{{ csrf_token }}"
                    }
                    $.post('/orders/pay', req_data, function(data){
                        if ( 1 == data.code ) {
                            // 用户未登录
                            location.href = "/users/login";
                        } else if (0 == data.code ) {
                            // 发起支付请求成功,跳转的地址
                            window.open(data.url);
                        } else {
                            alert(data.message);
                        }
                    });
                } 
            });

     后端视图业务逻辑

     用户必须是登陆的状态,通过继承自定义的装饰器

        1 接受前端传送的订单编号

        2 判断编号是否为空

        为空返回缺少订单的编号

         3  通过(订单的编号,用户,支付的方式,支付的状态),获取订单的信息表

           没查到返回订单有误

       下面睡固定的写法

       4  构建alipay支付工具对象(固定)

        

       alipay = AliPay(
                appid=settings.ALIPAY_APPID,  # 沙箱模式中的appid
                app_notify_url=None,  # 默认回调url
                app_private_key_path=os.path.join(settings.BASE_DIR, "apps/orders/app_private_key.pem"),
                alipay_public_key_path=os.path.join(settings.BASE_DIR, "apps/orders/alipay_public_key.pem"),  # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,
                sign_type="RSA2",  # RSA 或者 RSA2
                debug=True  # 默认False, 沙箱模式配置为true
            )

       

    5 借助alipay对象向支付宝发起支付请求 电脑网站支付,需要跳转到https://openapi.alipaydev.com/gateway.do? + order_string (固定)

     order_string = alipay.api_alipay_trade_page_pay(
                out_trade_no=order_id,  # 订单编号
                total_amount=str(order.total_amount),   # 订单金额
                subject="天天生鲜%s" % order_id,   # 订单描述信息
                return_url=None, # 订单成功返回的信息
                notify_url=None  # 可选, 不填则使用默认notify url
            )

      

    6返回 电脑网站支付,需要跳转到https://openapi.alipaydev.com/gateway.do? + order_string

    在orders.models中的OrderInfo类中添加以下的属性,表示订单的状态

    ORDER_STATUS_ENUM = {
            "UNPAID": 1,
            "UNSEND": 2,
            "UNRECEIVED": 3,
            "UNCOMMENT": 4,
            "FINISHED": 5
        }
    

     

    在orders.models中的OrderInfo类中添加以下的属性,表示支付方式的序号

     PAY_METHODS_ENUM = {
            "CASH": 1,
            "ALIPAY": 2
        }
    

      

    在settiing中添加访问支付宝的网址和支付宝的沙箱模式中的id

    # 支付宝的网址
    ALIPAY_URL = "https://openapi.alipaydev.com/gateway.do"
    ALIPAY_APPID = "2016081600258081"

    代码如下:

    class PayView(LoginRequiredJsonMixin, View):
        """支付宝支付视图"""
        def post(self, request):
            # 订单编号  order_id
            order_id = request.POST.get("order_id")
    
            if not order_id:
                return JsonResponse({"code": 2, "message": "缺失订单编号"})
    
            # 获取订单信息
            try:
                order = OrderInfo.objects.get(order_id=order_id, user=request.user,
                                              status=OrderInfo.ORDER_STATUS_ENUM["UNPAID"],
                                              pay_method=OrderInfo.PAY_METHODS_ENUM["ALIPAY"])
            except OrderInfo.DoesNotExist:
                return JsonResponse({"code": 3, "message": "订单信息错误"})
    
            # 构建alipay支付工具对象
            alipay = AliPay(
                appid=settings.ALIPAY_APPID,  # 沙箱模式中的appid
                app_notify_url=None,  # 默认回调url
                app_private_key_path=os.path.join(settings.BASE_DIR, "apps/orders/app_private_key.pem"),
                alipay_public_key_path=os.path.join(settings.BASE_DIR, "apps/orders/alipay_public_key.pem"),  # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,
                sign_type="RSA2",  # RSA 或者 RSA2
                debug=True  # 默认False, 沙箱模式配置为true
            )
    
            # 借助alipay对象,向支付宝发起支付请求
            # 电脑网站支付,需要跳转到https://openapi.alipaydev.com/gateway.do? + order_string
            order_string = alipay.api_alipay_trade_page_pay(
                out_trade_no=order_id,  # 订单编号
                total_amount=str(order.total_amount),   # 订单金额
                subject="天天生鲜%s" % order_id,   # 订单描述信息
                return_url=None,
                notify_url=None  # 可选, 不填则使用默认notify url
            )
    
            # 返回json数据
            alipay_url = settings.ALIPAY_URL + "?" + order_string
            return JsonResponse({"code": 0, "message": "发起支付成功", "url": alipay_url})
    View Code

      配置url

    url('^pay$', views.PayView.as_view(), name="pay"),

     当用户点击待支付按钮,就可以完成支付了

     检查支付的结果

    这个是没有公网,需要自己去向支付宝发送请求询问支付成功还是失败

     前端js的代码如下:

    红色区域表示新增的代码 :支付成功重新加载页面,失败显示失败的信息

    <script type="text/javascript">
    $('.oper_btn').click(function() {
    var order_id = $(this).attr("order_id");
    var order_status = $(this).attr("order_status");
    order_status = parseInt(order_status);
    // 只有待支付的状态才可以点击
    if (1 == order_status) {
    // 表示待支付
    var req_data ={
    order_id:order_id,
    csrfmiddlewaretoken: "{{ csrf_token }}"
    }
    $.post('/orders/pay', req_data, function(data){
    if ( 1 == data.code ) {
    // 用户未登录
    location.href = "/users/login";
    } else if (0 == data.code ) {
    // 发起支付请求成功
    window.open(data.url);
    // 向后端发起查询支付状态的请求
    $.get("/orders/check_pay?order_id="+order_id, function (resp_data) {
    if (0 == resp_data) {
    // 支付成功
    location.reload();
    } else {
    alert(resp_data.message);
    }
    });
    } else {
    alert(data.message);
    }
    });
    } else if (4 == order_status) {
    location.href = ("/orders/comment/" + order_id);
    }
    });
    </script>

     后端视图业务逻辑

     支付宝开发者文档 https://openhome.alipay.com/developmentDocument.htm

    后端视图的业务逻辑  

       1 用户必须是登陆的状态,

       2 通过get请求的方式接受用户传送过来的订单编号

        如果订单的编号不存在,返回订单信心缺少

       3 通过订单的(编号,用户,交易的状态是否为待支付和支付的方式是否为支付宝),查询对应的订单信息表

        如果不存在,返回订单信息错误

      4 通过whileTrue循环遍历查询用户交易的状态

        如果交易的状态码为10000和交易的状态为TRADE_SUCCESS说明交易成功,把支付宝的交易号保存在订单信息表的trade_id,订单的状态设为待评价,返回给前端

        如果交易的状态码为40004(表示支付宝还没生成订单)或者交易的状态码为10000并且交易的状态为用户待支付(WAIT_BUYER_PAY),延迟10scontinue

        else 返回支付失败

    完整的代码如下:

    class CheckPayStatusView(LoginRequiredJsonMixin, View):
        """检查支付结果"""
        def get(self, request):
            order_id = request.GET.get("order_id")
    
            if not order_id:
                return JsonResponse({"code": 2, "message": "缺少订单号"})
    
            # 获取订单信息
            try:
                order = OrderInfo.objects.get(order_id=order_id, user=request.user,
                                              status=OrderInfo.ORDER_STATUS_ENUM["UNPAID"],
                                              pay_method=OrderInfo.PAY_METHODS_ENUM["ALIPAY"])
            except OrderInfo.DoesNotExist:
                return JsonResponse({"code": 3, "message": "订单信息错误"})
    
            # 构建alipay支付工具对象
            alipay = AliPay(
                appid=settings.ALIPAY_APPID,  # 沙箱模式中的appid
                app_notify_url=None,  # 默认回调url
                app_private_key_path=os.path.join(settings.BASE_DIR, "apps/orders/app_private_key.pem"),
                alipay_public_key_path=os.path.join(settings.BASE_DIR, "apps/orders/alipay_public_key.pem"),  # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,
                sign_type="RSA2",  # RSA 或者 RSA2
                debug=True  # 默认False, 沙箱模式配置为true
            )
    
            # 借助alipay工具查询支付结果
            while True:
                response = alipay.api_alipay_trade_query(order_id)
                code = response.get("code")
                trade_status = response.get("trade_status")
                if code == "10000" and trade_status == "TRADE_SUCCESS":
                    # 表示用户支付成功
                    order.trade_id = response.get("trade_no") # 支付宝的交易标号
                    order.status = OrderInfo.ORDER_STATUS_ENUM["UNCOMMENT"]  # 设置订单状态为待评价
                    order.save()
                    return JsonResponse({"code": 0, "message": "支付成功"})
                elif code == "40004" or (code == "10000" and trade_status == "WAIT_BUYER_PAY"):
                    # 表示支付宝订单还没创建好, 或者用户还未支付
                    time.sleep(10)
                    continue
                else:
                    return JsonResponse({"code": 4, "message": "支付失败"})
    View Code

    配置url路径

    url('^check_pay$', views.CheckPayStatusView.as_view(), name="check_pay"),
    

      

      

     
     
     
  • 相关阅读:
    C#里边的控件缩写大全(比较规范)
    jQuery的一些备忘
    有趣的史实~
    值类型 VS 引用类型~
    一道笔试题和UML思想 ~
    数据绑定以及Container.DataItem几种方式与用法分析
    用户控件与自定义控件的异同
    .NET资源站点汇总~
    C#中抽象类和接口的区别
    弹出窗口的一些东西(一),备忘~
  • 原文地址:https://www.cnblogs.com/aaronthon/p/9347835.html
Copyright © 2011-2022 走看看