1. 程式人生 > >09 調用支付寶接口

09 調用支付寶接口

base .get else 訪問 best 登陸 ali cati num

安裝

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 調用支付寶接口