09 调用支付宝接口

Posted aaronthon

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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"),

  

  

以上是关于09 调用支付宝接口的主要内容,如果未能解决你的问题,请参考以下文章

在微信中如何调用支付宝接口

接入支付宝支付SDK

我用java怎么去实现支付宝接口,没有思路,求大神帮忙,谢谢,

php编程之如何调用支付宝支付接口的实现

Android手机APP怎么调用支付宝接口进行支付

java 支付宝支付接口 的 NotifyUrl 应该怎么返回success 官网上说打印输出 我用了println, 后来用return