欧美三级国产三级日韩三级_亚洲熟妇丰满大屁股熟妇_欧美亚洲成人一区二区三区_国产精品久久久久久模特

微信小程序支付功能詳細分析(一、預支付) - 新聞資訊 - 云南小程序開發(fā)|云南軟件開發(fā)|云南網(wǎng)站建設-昆明葵宇信息科技有限公司

159-8711-8523

云南網(wǎng)建設/小程序開發(fā)/軟件開發(fā)

知識

不管是網(wǎng)站,軟件還是小程序,都要直接或間接能為您產(chǎn)生價值,我們在追求其視覺表現(xiàn)的同時,更側(cè)重于功能的便捷,營銷的便利,運營的高效,讓網(wǎng)站成為營銷工具,讓軟件能切實提升企業(yè)內(nèi)部管理水平和效率。優(yōu)秀的程序為后期升級提供便捷的支持!

您當前位置>首頁 » 新聞資訊 » 小程序相關 >

微信小程序支付功能詳細分析(一、預支付)

發(fā)表時間:2020-10-19

發(fā)布人:葵宇科技

瀏覽次數(shù):121

微信小程序支付功能詳細分析

小記:最近在做微信小程序的支付,中間也遇到了很多問題,總結(jié)一下,給大家避個坑,也給自己記錄一下后面可以作為參考

概要

本文中只寫執(zhí)行邏輯,跟一些算法,不包含具體代碼內(nèi)容,目前開發(fā)采用的是微信小程序、nginx+uwsgi+python+flask

微信小程序支付
官方文檔:https://developers.weixin.qq.com/miniprogram/dev/framework/

整體邏輯

整體邏輯(來自微信官方開發(fā)文檔)首先先看下整體邏輯

整體邏輯
https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_4&index=3

這個是官方給出的 小程序支付的流程圖,我們來分布講解一下

首先先講解下邏輯,用戶點擊下單,并不是直接小程序發(fā)送給微信后臺服務器,而是小程序把數(shù)據(jù)傳輸給我們自己的服務器,通過我們自己的服務器跟微信后臺服務器交互后獲取支付數(shù)據(jù)傳輸給微信小程序客戶端,再由微信小程序通過統(tǒng)一的支付函數(shù),直接發(fā)送給微信后臺服務器,支付成功,成功后微信后臺服務器會給我們的服務器和微信小程序發(fā)支付成功信息。

為了方便理解,我們把我微信小程序簡稱(客戶端),我們自己的服務器簡稱(A服務器),微信后臺的服務器簡稱(B服務器)

可以看到我們在整個支付流程中, 向B服務器發(fā)送過兩次的支付請求,一次是A服務器發(fā)出,一次是微信小程序發(fā)出。 第一次稱為預支付,第二次才是下單

預支付

我們先講一下預支付
預支付就是A服務器使用統(tǒng)一下單命令向B服務器發(fā)送數(shù)據(jù)并返回一個json數(shù)據(jù),這個json數(shù)據(jù)到時候是要發(fā)送給客戶端,完成第二次下單操作的參數(shù)

預支付步驟:
預支付

關于 統(tǒng)一下單 需要幾個參數(shù)我們需要先獲取一下:
1、openid (用戶標識)
2、nonce_str (隨機字符串)
3、out_trade_no (商戶訂單號)
4、sign (簽名)

1、openid(用戶標識)

首先客戶端提起支付請求,我們需要先把微信客戶端的用戶登陸憑證獲取到,然后發(fā)送給A服務器

//微信小程序 js代碼
//微信登陸,獲取代碼,發(fā)送A服務器 并獲取結(jié)果(即openid)
wx.login({
        success: function (res) {	//登陸成功,獲取用戶登陸憑證 res.code
          if (res.code) {
            wx.request({		//發(fā)送數(shù)據(jù)給A服務器
              url: 'https://你自己的服務器',
              data: {
                code: res.code,         //用戶登陸憑證,這個后面用戶換取openid的東西 主要作用參考圖 2
                ordercode: ordercode,   //支付金額
              },
              method: 'post',
              success: function (res) {
                	//返回的數(shù)據(jù)我們待會在做詳細講解///
              }
            })
          } else {
            console.log('獲取用戶登錄態(tài)失敗!' + res.errMsg)
          }
        }
      });

圖二
圖2

wx.login
官方文檔:https://developers.weixin.qq.com/miniprogram/dev/api/open-api/login/wx.login.html

接下來的部分就全部是 A B兩個服務器之間的數(shù)據(jù)互換了
把A服務器剛才獲取到的數(shù)據(jù),發(fā)送給B服務器,獲取openid(這個相當于客戶的id,在我們自己的小程序中是唯一的,用于辨識是哪個用戶)

下面是openid獲取的演示

# A服務器 python
#后臺我使用的是python 只講下邏輯

#比如下面這個data就是前端發(fā)過來的數(shù)據(jù)
data:{
	code: "aaabbbcccc",         
   	ordercode: 100,
}


#定義一個獲取openid 的函數(shù),把整個data都傳進去
def getOpenID(kwargs):
    param = {
        'code': kwargs['code'],			#前端獲取到的用戶登陸憑證
        'appid': "wxd00000000000000",   #小程序的appid
        'secret': "000000000000000000000000",#商戶的密鑰
        'grant_type': 'authorization_code',  #這個直接固定死值就可以了
    }
    # 通過code獲取openid
    openIdUrl = 'https://api.weixin.qq.com/sns/jscode2session?appid={}&secret={}&js_code={}&grant_type=authorization_code'.format(
        param['appid'], param['secret'], param['code'])
    resp = requests.get(openIdUrl)
	#一定要使用get獲取,不用使用post
	#成功后的值
#	{
#  		"openid":"xxxxxxxxxxxxxxxx",
#  		"session_key":"xxxxxxxxxxxxx" 
#   }

    openId = json.loads(resp.text)
    return openId['openid']


getOpenID(data) #執(zhí)行函數(shù)

openid獲取
參考官方文檔:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html

目前我們獲取到了openid

2、nonce_str (隨機字符串)

這個作用主要是為了防止別人模仿發(fā)送假的數(shù)據(jù)給微信,不用太糾結(jié)作用,寫入就可以了,下面講下他的生成方法
官方解釋
在這里插入圖片描述

#A服務器 python
def get_nonce_str():
    char = "abcdefghijklmnopqrstuvwxyz0123456789"
    nonce_str = ""
    for i in range(0, 32):
        rad_num = random.randint(0, len(char) - 1)
        nonce_str  += char[rad_num]
    nonce_str = nonce_str .upper()  #注意:最后要全部處理成大寫
    return nonce_str 

隨機字符串
參考官方文檔:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=4_3

3、out_trade_no (商戶訂單號)

這個就是你自己定義一個訂單號,保證唯一性,可隨意定制

4、sign (簽名)

簽名,主要是防止被偽造,官方給出了簽名算法

簽名生成的通用步驟如下:

第一步,設所有發(fā)送或者接收到的數(shù)據(jù)為集合M,將集合M內(nèi)非空參數(shù)值的參數(shù)按照參數(shù)名ASCII碼從小到大排序(字典序),使用URL鍵值對的格式(即key1=value1&key2=value2…)拼接成字符串stringA。

特別注意以下重要規(guī)則:

◆ 參數(shù)名ASCII碼從小到大排序(字典序); ◆ 如果參數(shù)的值為空不參與簽名; ◆ 參數(shù)名區(qū)分大小寫; ◆
驗證調(diào)用返回或微信主動通知簽名時,傳送的sign參數(shù)不參與簽名,將生成的簽名與該sign值作校驗。 ◆
微信接口可能增加字段,驗證簽名時必須支持增加的擴展字段
第二步,在stringA最后拼接上key得到stringSignTemp字符串,并對stringSignTemp進行MD5運算,再將得到的字符串所有字符轉(zhuǎn)換為大寫,得到sign值signValue。

◆ key設置路徑:微信商戶平臺(pay.weixin.qq.com)–>賬戶設置–>API安全–>密鑰設置

我們這邊來實現(xiàn)一下

#A服務器 python

# MD5加密
def MD5(str):
    md5 = hashlib.md5()
    md5.update(str.encode('utf-8'))
    return md5.hexdigest()


#簽名
def getSign(kwargs):
    keys, paras = sorted(kwargs), []   #先排序
    paras = ['{}={}'.format(key, kwargs[key]) for key in keys if key != '']  #去除空值,把格式轉(zhuǎn)換成key=value
    stringA = '&'.join(paras)  #連接在一起

    stringSignTemp = stringA + '&key=' + "xxxxxxxxx" #添加密鑰
    sign = MD5(stringSignTemp).upper()  #MD5加密

    return sign
#1、根據(jù)key排序
#2、去除key為空的值
#3、json格式轉(zhuǎn)程字符串 key = value
#4、字符串添加密鑰
#5、MD5加密  并轉(zhuǎn)大寫

簽名
參考官方文檔:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=4_3

函數(shù)大家都會寫,那里面提到的參數(shù)到底是什么數(shù)據(jù)呢,其實就是統(tǒng)一下單你要提交的所有數(shù)據(jù)
在這里插入圖片描述

圖片
圖片文獻官方文檔:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_1#

就是把里面所有的必填項寫成json,其中的sign 不要寫進去,雖然他是必填,但不要寫進去,這點官方文檔沒有說明

#A服務器 python
pay_info = {
        "appid": "xxxxxxxxxxxxxxxxx",  #小程序的appid
        "mch_id": "xxxxxxxxxxxxxx",   #微信支付分配的商戶號
        "nonce_str": get_nonce_str(), #隨機字符串 參考2
        "body": "產(chǎn)品名稱",      
        "out_trade_no": out_trade_no, #商戶訂單號 參考3
        "total_fee": 1,              #費用
        "spbill_create_ip": "000.000.000.000",#就是你A服務器的ip
        "notify_url": "https://xxxxxx", #這個是支付成功后會返回支付詳情,就返回到你寫的這個網(wǎng)址
        "trade_type": "JSAPI",       #不用改
        "openid": openID,           #你剛才獲取的openid
    }

getSign(pay_info)   #把這個json去生成加密得到 sign

簽名雖然獲取完了,最后還要把剛才的要傳輸?shù)臄?shù)據(jù)xml格式化

pay_info['sign'] = getSign(pay_info) 
#注意:要先把生成的sign 放入到剛才的 json里面去,然后再去轉(zhuǎn)xml


#轉(zhuǎn)換成xml
def getxml(kwargs):
    

    # 生成xml
    xml = ''
    for key, value in kwargs.items():
        xml += '<{0}><{1}></{0}>\n'.format(key, value)
    xml = '<xml>{0}</xml>'.format(xml)
    xml = xml.encode('utf-8')
    # print(xml)wx
    return xml

此時所有數(shù)據(jù)都獲取完了,也xml格式化成 微信支付中統(tǒng)一下單的格式了,我們下面發(fā)送給B服務器,獲取后面第二步下單的數(shù)據(jù)就可以了

最后一步,統(tǒng)一下單
講幾個著重點:
發(fā)送的一定要是最后格式化的xml
post發(fā)送
發(fā)送的網(wǎng)址:https://api.mch.weixin.qq.com/pay/unifiedorder

def wxpay(xml):
    oUrl = 'https://api.mch.weixin.qq.com/pay/unifiedorder'
    resp = requests.post(Url, data=xml)
    return resp.content

統(tǒng)一下單
參考官方文檔:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_1#

以為結(jié)束了,不,這里有個小坑,一定要注意下

獲取到的數(shù)據(jù) 是不能直接傳給 客戶端的 傳給客戶端的需要是(第2步 下單)所需要的數(shù)據(jù)

這個我們下一張再講吧
在這里插入圖片描述

藍框部分咱們已經(jīng)全部完成了

相關案例查看更多