小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

Django整合微信h5支付

 看見就非常 2020-04-29

    終于在踩完了無數(shù)坑之后,發(fā)現(xiàn)這個流程必須記錄下來。在這之前,本人不僅嘗試過網(wǎng)上各種各樣的帖子,也參考了微信支付的官方文檔,都最后都是發(fā)現(xiàn):要么難以理解,要么甚至按照微信支付的官方文檔也會遇到問題。

    雖然如果完全參考官方的文檔會被誤導,但是其中一部分還是可以參考的。

    首先來看要準備的環(huán)境:

    1.認證的微信公眾號,并且開通了微信支付

    2.開通商戶平臺賬號

    3.帶域名的服務器

    以上三點是對接微信h5支付的前提條件,接下來我們可以參考微信支付的官方文檔:由于是h5頁面調(diào)用的微信支付,所以這里點擊鏈接后選擇JSAPI支付。在統(tǒng)一下單的列表中,微信給出了需要請求的API以及參數(shù)。由于我參考的其他的技術貼自己請求微信的API一直沒成功,所以最后我還是直接調(diào)用了微信官方對支付封裝好的代碼,代碼可以在github上下載。下載好之后,需要分別將weixin文件夾中的config.py、lib.py和pay.py腳本文件拷貝到我們的工程目錄下。拷貝完成后對這些腳本文件稍作配置:

    config.py腳本中需要配置的都是些微信公眾號的信息,像APPID、APPSECRET等,其中都有注釋。登錄到微信公眾平臺,在基本配置中可以看到一下信息:

    

    這里就有APPID、APPSECRET和TOKEN,服務器地址要配置成服務器上的一個接口(服務器帶上域名),在提交配置的時候微信會對我們配置的這個接口發(fā)送一個請求,接口需要接收微信傳來的參數(shù)以及返回正確的響應才能配置成功。服務器上的接口如下:

  1. class WXRest(APIView):
  2. authentication_classes = []
  3. permission_classes = []
  4. def get(self, request):
  5. signature = request.GET.get('signature')
  6. timestamp = request.GET.get('timestamp')
  7. nonce = request.GET.get('nonce')
  8. echostr = request.GET.get('echostr')
  9. wechat_instance = WechatBasic(conf=wxConf)
  10. if not wechat_instance.check_signature(signature=signature, timestamp=timestamp, nonce=nonce):
  11. return HttpResponseBadRequest('Verify Failed')
  12. else:
  13. return HttpResponse(echostr, content_type="application/json")

    wxConf的配置如下:

  1. wxConf = WechatConf(
  2. token='xxxxxx',
  3. appid=SOCIAL_AUTH_WEIXIN_APPID,
  4. appsecret=SOCIAL_AUTH_WEIXIN_SECRET,
  5. encrypt_mode='normal',
  6. encoding_aes_key='xxxxxx'
  7. )

    其中token需要填寫之前公眾號開發(fā)信息中的令牌(Token),appid就是公眾號中的開發(fā)者ID,appsecret為開發(fā)者密碼,encoding_aes_key為服務器配置項中的服務器加解密密鑰。

    我這里使用的drf的API View,注意其中的

  1. authentication_classes = []
  2. permission_classes = []

    這兩句是取消該接口的token認證和登錄認證,否則如果接口上有任何的權限認證,微信的請求都是不成功的。

    config.py腳本中剩下的商戶ID MCHID和商戶支付密鑰KEY則需要登錄到微信商戶平臺中獲取。

    做好這些配置之后,就可以正式開始View的編寫了:

  1. from utils.wechatUtils.pay import JsApi_pub, UnifiedOrder_pub
  2. class WxPayConfig(APIView):
  3. def post(self, request):
  4. money = request.data[u"number"]
  5. admin_user = AdminUser.objects.filter(username=request.user.username)[0]
  6. master = Master.objects.filter(admin_user=admin_user)[0]
  7. socialAccounts = SocialAccounts.objects.filter(admin_user=admin_user)[0]
  8. openid = socialAccounts.openid
  9. money = int(float(money)*100)
  10. out_trade_no = genOrder(master.phone)
  11. jsApi = JsApi_pub()
  12. unifiedOrder = UnifiedOrder_pub()
  13. unifiedOrder.setParameter("openid", openid)
  14. unifiedOrder.setParameter("body", "儲值卡充值")
  15. unifiedOrder.setParameter("out_trade_no", out_trade_no)
  16. unifiedOrder.setParameter("total_fee", str(money))
  17. unifiedOrder.setParameter("notify_url", NOTIFY_URL)
  18. unifiedOrder.setParameter("trade_type", "JSAPI")
  19. prepay_id = unifiedOrder.getPrepayId()
  20. jsApi.setPrepayId(prepay_id)
  21. jsApiParameters = jsApi.getParameters()
  22. conn = redis.StrictRedis()
  23. conn.set("out_trade_no_" + out_trade_no, json.dumps({"type": "儲值卡充值", "admin_user": admin_user.id},
  24. ensure_ascii=False), 60 * 10)
  25. return HttpResponse(json.dumps(json.loads(jsApiParameters)), content_type="application/json")

      這里同樣是使用drf的APIView,number參數(shù)是從前端提交的支付金額,從微信提供的pay.py中導入JsApi_pub和UnifiedOrder_pub,然后設置所需的參數(shù)。其中參數(shù)openid就是用戶微信的openid,body是商品名稱,out_trade_no為我們自己服務器生成的訂單號,total_fee就是付款金額,notify_url為微信支付成功后回調(diào)的我們服務器的URL,trade_type參數(shù)為JSAPI表示支付類型為h5頁面支付。填寫完這些參數(shù)后,調(diào)用UnifiedOrder_pub類中的getPrepayId函數(shù)獲得prepay_id,并進行設置。最后將調(diào)用jsApi.getParameters()函數(shù)返回的結果返回到前端。

      生成參數(shù)out_trade_no的函數(shù)如下:

  1. def genOrder(phone="176******"):
  2. id_number = str(phone) + str(time.time())
  3. resId = str(uuid.uuid3(uuid.NAMESPACE_URL, id_number))
  4. resId = u"".join(re.findall("\d+", resId))
  5. return resId

    上面的代碼片段是根據(jù)用戶的手機生成對應的唯一下單ID。當支付成功后,微信會將支付結果以post請求的發(fā)送提交到NOTIFY_URL,對應的View接受參數(shù)如下:

  1. class PayResult(APIView):
  2. authentication_classes = []
  3. permission_classes = []
  4. def get(self, request):
  5. self.post(request)
  6. def post(self, request):
  7. if request.body != "":
  8. xmlDict = xmlParse(request.body)
  9. print json.dumps(xmlDict, ensure_ascii=False)
  10. if xmlDict.has_key(u'return_code') and xmlDict[u'return_code'] == u'SUCCESS':
  11. total_fee = xmlDict[u'total_fee']
  12. out_trade_no = xmlDict[u'out_trade_no']
  13. try:
  14. with transaction.atomic():
  15. conn = redis.StrictRedis()
  16. data = conn.get("out_trade_no_" + out_trade_no)
  17. if data is not None:
  18. jsonData = json.loads(data)
  19. admin_user_id = jsonData[u"admin_user"]
  20. if jsonData[u"type"] == u"儲值卡充值":
  21. admin_user = AdminUser.objects.filter(id=admin_user_id)[0]
  22. assets = Assets.objects.filter(admin_user=admin_user)
  23. if len(assets) == 0:
  24. assets = Assets()
  25. assets.assets = float(total_fee) / 100
  26. assets.admin_user = admin_user
  27. else:
  28. assets = assets[0]
  29. assets.assets = float(assets.assets) + float(total_fee) / 100
  30. assets.save()
  31. assetsDetail = AssetsDetail()
  32. assetsDetail.balance = float(total_fee) / 100
  33. assetsDetail.type = 1
  34. assetsDetail.note = jsonData[u"type"]
  35. assetsDetail.admin_user = admin_user
  36. assetsDetail.save()
  37. except BaseException as e:
  38. print e.message
  39. return_data = {"return_code": "SUCCESS", "return_msg": "OK"}
  40. return HttpResponse(trans_dict_to_xml(return_data), content_type="application/xml")

    當支付成功時,微信提交的參數(shù)中會包含return_code并且值為SUCCESS,這里需要注意的是,微信提交的參數(shù)類型為xml,且我們返回給微信的數(shù)據(jù)類型也為xml,若處理成功,需要返回:

  1. <xml>
  2. <return_code><![CDATA[SUCCESS]]></return_code>
  3. <return_msg><![CDATA[OK]]></return_msg>
  4. </xml>

    注意這里的格式并不是常見的xml格式,而是微信它自己的<![CDATA[,這也是讓人很麻煩的地方。將json數(shù)據(jù)封裝成微信的xml格式數(shù)據(jù)函數(shù)如下:

  1. def trans_dict_to_xml(data_dict):
  2. data_xml = []
  3. for k in sorted(data_dict.keys()):
  4. v = data_dict.get(k)
  5. if k == 'detail' and not v.startswith('<![CDATA['):
  6. v = '<![CDATA[{}]]>'.format(v)
  7. data_xml.append('<{key}>{value}</{key}>'.format(key=k, value=v))
  8. return '<xml>{}</xml>'.format(''.join(data_xml)).encode('utf-8')

    最后,在前端處理我們后臺返回的結果并調(diào)起微信支付:

  1. sendAjax({"number":number},"/wx-pay-config",function (data) {
  2. wx.config({
  3. debug:false,
  4. appId:data["appId"],
  5. timestamp:data["timeStamp"],
  6. nonceStr:data["nonceStr"],
  7. signature:data["paySign"],
  8. package:data["package"]
  9. });
  10. wx.ready(function () {
  11. wx.chooseWXPay({
  12. timestamp: data["timeStamp"], // 支付簽名時間戳
  13. nonceStr: data["nonceStr"], // 支付簽名隨機串,不長于32 位
  14. package: data["package"], // 統(tǒng)一支付接口返回的prepay_id參數(shù)值,提交格式如:prepay_id=***)
  15. signType: "MD5", // 簽名方式,默認為'SHA1',使用新版支付需傳入'MD5'
  16. paySign: data["paySign"], // 支付簽名
  17. success: function (res) {
  18. //支付成功
  19. mui.alert("支付成功");
  20. },
  21. cancel: function (res) {
  22. //支付取消
  23. mui.alert("支付已取消");
  24. }
  25. });
  26. });
  27. wx.error(function (res) {
  28. console.log("error:" + res);
  29. });
  30. });

sendAjax是我自己封裝的一個提交POST形式的ajax函數(shù),大家使用普通的ajax發(fā)送post請求就可以了。這里需要注意的是,最后我調(diào)用了一個wx.error的函數(shù),我原以為是在支付出錯時調(diào)用的,但經(jīng)過測試后發(fā)現(xiàn):即使支付成功了,這個error函數(shù)依然會被執(zhí)行,很容易被誤導,以為支付沒成功。這里值得一提的是,在微信官方文檔中,前端調(diào)起支付的代碼如下:

  1. function onBridgeReady(){
  2. WeixinJSBridge.invoke(
  3. 'getBrandWCPayRequest', {
  4. "appId":"wx2421b1c4370ec43b", //公眾號名稱,由商戶傳入
  5. "timeStamp":"1395712654", //時間戳,自1970年以來的秒數(shù)
  6. "nonceStr":"e61463f8efa94090b1f366cccfbbb444", //隨機串
  7. "package":"prepay_id=u802345jgfjsdfgsdg888",
  8. "signType":"MD5", //微信簽名方式:
  9. "paySign":"70EA570631E4BB79628FBCA90534C63FF7FADD89" //微信簽名
  10. },
  11. function(res){
  12. if(res.err_msg == "get_brand_wcpay_request:ok" ){
  13. // 使用以上方式判斷前端返回,微信團隊鄭重提示:
  14. //res.err_msg將在用戶支付成功后返回ok,但并不保證它絕對可靠。
  15. }
  16. });
  17. }
  18. if (typeof WeixinJSBridge == "undefined"){
  19. if( document.addEventListener ){
  20. document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
  21. }else if (document.attachEvent){
  22. document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
  23. document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
  24. }
  25. }else{
  26. onBridgeReady();
  27. }

經(jīng)過測試后發(fā)現(xiàn),這樣寫并不能調(diào)起支付,是一個完全沒反應的狀態(tài)。這是微信文檔很坑的地方,需要大家特別注意。

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多