前后端分離djangorestframework—— 接入支付寶支付平台


支付寶

簡介

支付寶是什么不用多說了,本次教程適合初學者

 

前提准備

話不多說,干就完了

 

1.注冊開發者賬號,設置公鑰私鑰

首先進入支付寶開發者平台:傳送門 ,有賬號直接登錄,沒賬號用你平時用來付款收錢的賬號登錄,然后用這個賬號激活注冊成開發者賬號就行了

登錄之后點開發中心:

先用沙箱測試一下,點研發服務

 

 跳轉到此頁面,設置一個公鑰

 

 

先點查看公鑰生成:

 

 進入開發文檔:傳送門  根據文檔步驟下載秘鑰生成工具,根據說明文檔運行程序

 

 

本次教程使用的是Python,所以一定要選非java,然后點擊生成秘鑰

 

 再點打開秘鑰路徑就可以看到已經生成了兩個文件:

 

用這里的公鑰和私鑰,填入剛才那個設置頁面:

如果在保存時提示什么公鑰簽名啥啥的,反正不成功的提示,利用秘鑰生成工具重新生成一次填入即可

接着按這里的文檔走就行:傳送門  需要一個安卓手機下載沙箱版的支付寶作為測試

 

2.安裝sdk 

 

之前使用支付寶,都要去github上download大神寫的sdk,現在pyi社區已經有官方的sdk了:傳送門  所以,直接pip install alipay-sdk-python 安裝:

 但是到最后會報錯:

 

 

然后看到說是因為安裝支付寶的sdk時,由於需要安裝這個庫,而這個庫需要依賴微軟的visual c++才行,這就尷尬了,據查,要安裝visual C++最好的辦法是,下載visual Studio集成開發工具,注意不是visual studio code,兩個是不同的軟件,雖然都可以當開發工具,我的理解就是visual studio比visual studio code多了那些需要的運行庫

 visual studio官方下載鏈接最新版   另外據網查,可以只安裝visual studio 2015版就行,visual studio 2015下載鏈接 ,總共有幾個G,解壓並安裝,只安裝這個c++ 2015

 

等好長一會兒:

 

 然后再安裝支付寶的sdk看看,還是不行

 按報錯提示,那個c1.exe不被認識,所以還要設置環境變量:變量名:VCINSTALLDIR,變量值就是vc的路徑

 

設置了環境變量后關閉cmd,重新打開cmd, 先使用命令設置:set CL=/FI"%VCINSTALLDIR%\\INCLUDE\\stdint.h" 這條命令是為了讓剛才我們設置的環境變量生效

 

然后pip 安裝,終於成功了

 

注:如果報錯:UnicodeDecodeError: 'utf-8' codec can't decode byte... 將CMD的終端編碼用“CHCP 65001”命令改為“UTF-8”后再安裝即可

 

進入支付寶支付開發

 

好接着進入真正的開發階段了,本次選用【電腦頁面支付】:

 

然后進到支付寶的api文檔:傳送門

選用  統一收單下單支付接口  

進入的目錄就不展示了,里面的參數配置就是正式的支付接口,這個就根據自己實際情況配置了,本次我們只用沙箱賬號測試一下就行了,和正式的配置是一樣的,因為正式的配置要認證商家才行,所以為了方便且精簡的演示,就用沙箱賬號了

 

在前面設置公鑰私鑰那個頁面,把安卓版的沙箱支付寶下載安裝好,使用這里的賬號密碼登錄:

 

 准備好之后,現在進入真正的開發了。

 

1.創建一個django項目,一個簡單的支付寶充值話費的

 

配置文件里導入rest_framework  app,設置url,其中pay則是一會兒要用到的測試url

html文件:

 

 

view,就按照pypi社區上支付寶給的案例調整代碼就行:

 

#!/usr/bin/env python # -*- coding: utf-8 -*-
import logging import traceback from alipay.aop.api.AlipayClientConfig import AlipayClientConfig from alipay.aop.api.DefaultAlipayClient import DefaultAlipayClient from alipay.aop.api.FileItem import FileItem from alipay.aop.api.domain.AlipayTradeAppPayModel import AlipayTradeAppPayModel from alipay.aop.api.domain.AlipayTradePagePayModel import AlipayTradePagePayModel from alipay.aop.api.domain.AlipayTradePayModel import AlipayTradePayModel from alipay.aop.api.domain.GoodsDetail import GoodsDetail from alipay.aop.api.domain.SettleDetailInfo import SettleDetailInfo from alipay.aop.api.domain.SettleInfo import SettleInfo from alipay.aop.api.domain.SubMerchant import SubMerchant from alipay.aop.api.request.AlipayOfflineMaterialImageUploadRequest import AlipayOfflineMaterialImageUploadRequest from alipay.aop.api.request.AlipayTradeAppPayRequest import AlipayTradeAppPayRequest from alipay.aop.api.request.AlipayTradePagePayRequest import AlipayTradePagePayRequest from alipay.aop.api.request.AlipayTradePayRequest import AlipayTradePayRequest from alipay.aop.api.response.AlipayOfflineMaterialImageUploadResponse import AlipayOfflineMaterialImageUploadResponse from alipay.aop.api.response.AlipayTradePayResponse import AlipayTradePayResponse logging.basicConfig( level=logging.INFO, format='%(asctime)s %(levelname)s %(message)s', filemode='a',) logger = logging.getLogger('') if __name__ == '__main__': """ 設置配置,包括支付寶網關地址、app_id、應用私鑰、支付寶公鑰等,其他配置值可以查看AlipayClientConfig的定義。 """ alipay_client_config = AlipayClientConfig() alipay_client_config.server_url = 'https://openapi.alipay.com/gateway.do' alipay_client_config.app_id = '[your app_id]' alipay_client_config.app_private_key = '[your app private key]' alipay_client_config.alipay_public_key = '[alipay public key]'

    """ 得到客戶端對象。 注意,一個alipay_client_config對象對應一個DefaultAlipayClient,定義DefaultAlipayClient對象后,alipay_client_config不得修改,如果想使用不同的配置,請定義不同的DefaultAlipayClient。 logger參數用於打印日志,不傳則不打印,建議傳遞。 """ client = DefaultAlipayClient(alipay_client_config=alipay_client_config, logger=logger) """ 系統接口示例:alipay.trade.pay """
    # 對照接口文檔,構造請求對象
    model = AlipayTradePayModel() model.auth_code = "282877775259787048" model.body = "Iphone6 16G" goods_list = list() goods1 = GoodsDetail() goods1.goods_id = "apple-01" goods1.goods_name = "ipad" goods1.price = 10 goods1.quantity = 1 goods_list.append(goods1) model.goods_detail = goods_list model.operator_id = "yx_001" model.out_trade_no = "20180510AB014" model.product_code = "FACE_TO_FACE_PAYMENT" model.scene = "bar_code" model.store_id = "" model.subject = "huabeitest" model.timeout_express = "90m" model.total_amount = 1 request = AlipayTradePayRequest(biz_model=model) # 如果有auth_token、app_auth_token等其他公共參數,放在udf_params中
    # udf_params = dict()
    # from alipay.aop.api.constant.ParamConstants import *
    # udf_params[P_APP_AUTH_TOKEN] = "xxxxxxx"
    # request.udf_params = udf_params
    # 執行請求,執行過程中如果發生異常,會拋出,請打印異常棧
    response_content = None try: response_content = client.execute(request) except Exception as e: print(traceback.format_exc()) if not response_content: print("failed execute") else: response = AlipayTradePayResponse() # 解析響應結果
 response.parse_response_content(response_content) print(response.body) if response.is_success(): # 如果業務成功,則通過respnse屬性獲取需要的值
            print("get response trade_no:" + response.trade_no) else: # 如果業務失敗,則從錯誤碼中可以得知錯誤情況,具體錯誤碼信息可以查看接口文檔
            print(response.code + "," + response.msg + "," + response.sub_code + "," + response.sub_msg) """ 帶文件的系統接口示例:alipay.offline.material.image.upload """
    # 如果沒有找到對應Model類,則直接使用Request類,屬性在Request類中
    request = AlipayOfflineMaterialImageUploadRequest() request.image_name = "我的店" request.image_type = "jpg"
    # 設置文件參數
    f = open("/Users/foo/Downloads/IMG.jpg", "rb") request.image_content = FileItem(file_name="IMG.jpg", file_content=f.read()) f.close() response_content = None try: response_content = client.execute(request) except Exception as e: print(traceback.format_exc()) if not response_content: print("failed execute") else: response = AlipayOfflineMaterialImageUploadResponse() response.parse_response_content(response_content) if response.is_success(): print("get response image_url:" + response.image_url) else: print(response.code + "," + response.msg + "," + response.sub_code + "," + response.sub_msg) """ 頁面接口示例:alipay.trade.page.pay """
    # 對照接口文檔,構造請求對象
    model = AlipayTradePagePayModel() model.out_trade_no = "pay201805020000226" model.total_amount = 50 model.subject = "測試" model.body = "支付寶測試" model.product_code = "FAST_INSTANT_TRADE_PAY" settle_detail_info = SettleDetailInfo() settle_detail_info.amount = 50 settle_detail_info.trans_in_type = "userId" settle_detail_info.trans_in = "2088302300165604" settle_detail_infos = list() settle_detail_infos.append(settle_detail_info) settle_info = SettleInfo() settle_info.settle_detail_infos = settle_detail_infos model.settle_info = settle_info sub_merchant = SubMerchant() sub_merchant.merchant_id = "2088301300153242" model.sub_merchant = sub_merchant request = AlipayTradePagePayRequest(biz_model=model) # 得到構造的請求,如果http_method是GET,則是一個帶完成請求參數的url,如果http_method是POST,則是一段HTML表單片段
    response = client.page_execute(request, http_method="GET") print("alipay.trade.page.pay response:" + response) """ 構造喚起支付寶客戶端支付時傳遞的請求串示例:alipay.trade.app.pay """ model = AlipayTradeAppPayModel() model.timeout_express = "90m" model.total_amount = "9.00" model.seller_id = "2088301194649043" model.product_code = "QUICK_MSECURITY_PAY" model.body = "Iphone6 16G" model.subject = "iphone" model.out_trade_no = "201800000001201" request = AlipayTradeAppPayRequest(biz_model=model) response = client.sdk_execute(request) print("alipay.trade.app.pay response:" + response)
pypi社區上支付寶官方案例
#!/usr/bin/env python # -*- coding: utf-8 -*-
from alipay.aop.api.AlipayClientConfig import AlipayClientConfig from alipay.aop.api.DefaultAlipayClient import DefaultAlipayClient from alipay.aop.api.domain.AlipayTradePagePayModel import AlipayTradePagePayModel from alipay.aop.api.request.AlipayTradePagePayRequest import AlipayTradePagePayRequest from rest_framework.views import APIView from rest_framework.response import Response from django.shortcuts import render, redirect, HttpResponse def alipayclient(): """ 設置配置,包括支付寶網關地址、app_id、應用私鑰、支付寶公鑰等,其他配置值可以查看AlipayClientConfig的定義。 """ alipay_client_config = AlipayClientConfig() alipay_client_config.server_url = 'https://openapi.alipay.com/gateway.do' alipay_client_config.app_id = '您的app_Id' with open("keys/private_key.txt") as f: alipay_client_config.app_private_key = f.read() # 阿里的公鑰
    with open("keys/public_key.txt") as f: alipay_client_config.alipay_public_key = f.read() """ 得到客戶端對象。 注意,一個alipay_client_config對象對應一個DefaultAlipayClient,定義DefaultAlipayClient對象后,alipay_client_config不得修改,如果想使用不同的配置,請定義不同的DefaultAlipayClient。 logger參數用於打印日志,不傳則不打印,建議傳遞。 """ client = DefaultAlipayClient(alipay_client_config=alipay_client_config) return client """ 系統接口示例:alipay.trade.pay """


class AlipayView(APIView): def get(self, request): return render(request, 'pay.html') def post(self, request): money = request.data.get('money') if not money.isdigit(): return Response('錯誤,只能是數字') money = int(money) client = alipayclient() """ 頁面接口示例:alipay.trade.page.pay """
        # 對照接口文檔,構造請求對象
        model = AlipayTradePagePayModel() import time model.out_trade_no = 'pay201805020000226' model.total_amount = money model.subject = "測試" model.body = "支付寶測試" model.product_code = "FAST_INSTANT_TRADE_PAY" request = AlipayTradePagePayRequest(biz_model=model) # 得到構造的請求,如果http_method是GET,則是一個帶完成請求參數的url,如果http_method是POST,則是一段HTML表單片段
        response = client.page_execute(request, http_method="GET") print("alipay.trade.page.pay response:" + response) return redirect(response)
views

 

from django.contrib import admin from django.urls import path from app.views import AlipayView urlpatterns = [ path('admin/', admin.site.urls), path('pay/',AlipayView.as_view()), ]
urls  
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>支付寶電腦端支付-話費充值</title>
</head>
<body>

<form method="post">
    {% csrf_token %}
    <label for="money">金額:</label>
    <input type="text" placeholder="請輸入充值金額" id="money" name="money">
    <label for="phone">號碼:</label>
    <input type="text" value="183XXXXX" id="phone" name="phone">
    <input type="submit" value="立即支付寶充值">
</form>
</body>
</html>
pay.html

 

 

 

 

 

 

然后重啟項目: 

注意,有坑,真的有坑,照這么設置啟動,點擊支付的時候會跳到這個頁面:

 

第一個坑:

 

 

 

反正就這兩個頁面,無效的appID,其實我用的那個ID就是支付寶沙箱給的ID號,所以不可能有錯,但是注意了,我們用的是沙箱賬號,而我們直接拷貝的支付寶給的案例,用的url是【openapi.alipay.com】,這個url是正式的url,並不是沙箱測試的url,所以沙箱測試的url是【https://openapi.alipaydev.com/gateway.do】

 

 

第二個坑: 

修改url之后,再次提交,還是說訂單信息有錯誤,

 

 

到底是哪里的問題呢?再檢查打碼,還是剛才的邏輯,沙箱賬號啊,那么在初始化支付寶配置時,讀源碼得,需要添加這個參數 【sandbox_debug = True】:

 

第三個坑:

按上面的修改重啟,還是報錯: 

 

 

 

查看支付寶給的這個錯誤代碼解析,交易信息被篡改,好像也沒有說清楚啥問題

 

我試着改了下這個流水號,把它改成了用事件戳隨機生成的,【model.out_trade_no = "pay" + str(time.time())】

 

重啟項目,輸入金額23

 

 

 

點擊立即支付寶充值,這頁面終於出來了

 

 

那么那個流水號有多大作用呢?我直接刪除看看:

 

 

 

那么就得必須帶上它了

 

但是支付寶官方sdk里給的案例也貌似沒有說清楚啊,只是說看着像時間戳:

但是也沒說這玩意得按時間戳來實時接收,還不能寫死了,其實呢,仔細一想,這個流水號是不是得按當時付款時間來啊?難道以后每個時間段支付的都是同一個流水號?這不亂套了嗎?支付寶官方沒有提的原因,我猜啊,很大可能,是因為之前不是有大神寫過sdk了嘛,那么那些參數或許在哪個大神的sdk里有解釋了,而官方的這個sdk是之后發布的,所以可能開發者以為之前這老哥都開發過了,所以這些沒必要再提了。好的,反正這里有個坑,注意就行了

 

接着后面的操作,打開手機,用那個沙箱支付寶app登錄,掃碼支付:

 

2.完善代碼 

可以支付了對吧,然后按個訂單流水號就是剛才設置的那個咯,但是電腦頁面還是這樣,沒有任何反饋啊,作為商家我們根本不知道買家那邊什么情況,到底支付沒有也不知道對吧,不可能一個一個的去自己賬單里查賬吧?如果人多呢,幾個人同時支付怎么辦呢?

 

 

所以,這里還得配置一下,再寫一個url來接收一下數據,並返回支付結果:

url:

 

view:

主視圖類添加兩個url屬性

 

 新的url對應的識圖類:

 

重啟項目,支付查看結果:

 

 

 

 

 

 

 

 終端打印的結果:

 

 

OK,終於完事兒了

 

 

相關代碼:

 

from django.contrib import admin from django.urls import path from app.views import AlipayView from app.views import PayHandlerView urlpatterns = [ path('admin/', admin.site.urls), path('pay/',AlipayView.as_view()), path('alipay_handler',PayHandlerView.as_view()) ]
url
#!/usr/bin/env python # -*- coding: utf-8 -*-
from alipay.aop.api.AlipayClientConfig import AlipayClientConfig from alipay.aop.api.DefaultAlipayClient import DefaultAlipayClient from alipay.aop.api.domain.AlipayTradePagePayModel import AlipayTradePagePayModel from alipay.aop.api.request.AlipayTradePagePayRequest import AlipayTradePagePayRequest from rest_framework.views import APIView from rest_framework.response import Response from django.shortcuts import render, redirect, HttpResponse def alipayclient(): """ 設置配置,包括支付寶網關地址、app_id、應用私鑰、支付寶公鑰等,其他配置值可以查看AlipayClientConfig的定義。 """ alipay_client_config = AlipayClientConfig(sandbox_debug=True) alipay_client_config.server_url = 'https://openapi.alipaydev.com/gateway.do' alipay_client_config.app_id = '您的app_id' with open("keys/private_key.txt") as f: alipay_client_config.app_private_key = f.read() # 阿里的公鑰
    with open("keys/public_key.txt") as f: alipay_client_config.alipay_public_key = f.read() """ 得到客戶端對象。 注意,一個alipay_client_config對象對應一個DefaultAlipayClient,定義DefaultAlipayClient對象后,alipay_client_config不得修改,如果想使用不同的配置,請定義不同的DefaultAlipayClient。 logger參數用於打印日志,不傳則不打印,建議傳遞。 """ client = DefaultAlipayClient(alipay_client_config=alipay_client_config) return client """ 系統接口示例:alipay.trade.pay """


class AlipayView(APIView): def get(self, request): return render(request, 'pay.html') def post(self, request): money = request.data.get('money') if not money.isdigit(): return Response('錯誤,只能是數字') money = int(money) client = alipayclient() """ 頁面接口示例:alipay.trade.page.pay """
        # 對照接口文檔,構造請求對象
        model = AlipayTradePagePayModel() import time model.out_trade_no = 'pay' + str(time.time()) model.total_amount = money model.subject = "測試" model.body = "支付寶測試" model.product_code = "FAST_INSTANT_TRADE_PAY" request = AlipayTradePagePayRequest(biz_model=model) # 得到構造的請求,如果http_method是GET,則是一個帶完成請求參數的url,如果http_method是POST,則是一段HTML表單片段
        # get請求 用戶支付成功后返回的頁面請求地址,這個可以是公網地址
        request.return_url = "http://127.0.0.1:8002/alipay_handler"
        # post請求 用戶支付成功通知商戶的請求地址
        request.notify_url = "http://127.0.0.1:8002/alipay_handler" response = client.page_execute(request, http_method="GET") print("alipay.trade.page.pay response:" + response) return redirect(response) class PayHandlerView(APIView): def get(self, request): # return_url的回調地址
        print(request.data) # 用戶支付成功之后回到哪
        return HttpResponse("用戶支付成功") def post(self, request): print(request.data) return HttpResponse("notify_url")
views

html文件沒變,同上

 

總結:

  • 就是安裝sdk的時候很煩人,如果你覺得不習慣,可以用github上那些大神寫的sdk。我個人覺得,官方的只是安裝有點繁瑣,后面的配置是挺簡單的
  • 在使用沙箱測試支付的時候的時候注意那三個坑就行了,因為沙箱測試和正式的支付還是與差距的

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM