業務流程
這個微信官網說的還是很詳細的,還配了圖。我還要再說一次。
用戶點擊一個支付按鈕-->{後台一大推處理}-->用戶看到了一個輸入密碼的介面,包含金額等一些資訊-->用戶輸入密碼後出來一個支付成功的頁面(這部分流程都是微信自己完成的,我們什麼都不用做)-->返回系統自己的頁面(總不能讓用戶一直看著一個支付完成的頁面吧。花了錢,正心疼的,趕緊跳轉~一會兒後悔了,申請退款怎麼整。做不做沒有啥關係,反正我還沒做呢)
2)調用統一下單接口獲取預付id
#3)H5調起微信支付的內建JS
4)支付完成後,微信回呼URL的處理
#看著大段的文字,是不是很不爽。忘記了在哪裡看到的一句話。 One picture instead thousands of words. (圖中紅色部分是我們需要做的。好像也沒有多少
本文最主要的部分開始了(想直接看程式碼,貼上程式碼,你也不一定能看懂,不是說程式碼難,各種分離,各種類,不直接。 key0 還是得回來乖乖的對參數。笑話。的詳細說明。 ##appid ==應用ID==登陸微信公眾號後台-開發-基本配置mch_id == 微信支付商家號碼==登陸微信支付後台,即可看到
#device_info ==設備號碼==終端設備號碼(門市號碼或收銀設備ID),注意:PC網頁或公眾號碼內支付請傳"WEB"
body==商品描述==商品或支付單簡要描述(不知道是什麼鬼,沒關係,先隨便傳個字符串,隨便的傳個英文的字符串。你會為你這個時候的英明決定打個滿分。如果是中文,可能會遇到毫無頭緒的簽章錯誤,嚴重者開始懷疑人生)
trade_type==交易類型==取值如下:JSAPI,NATIVE,APP。
ps:JSAPI--公眾號支付、NATIVE--原生掃碼支付、APP--app支付,統一下單接口trade_type的傳參可參考這裡。單獨的支付接口,不呼叫統一下單接口
nonce_str==隨機字串==隨機字串,不長於32位
ps:小夥伴們可能會對nonce這個命名,很詔異,微信team的人,都是逗必嗎~。在我不懈的努力下,
發現了這個。 nonce ==number used once.恍然大悟的趕腳。
notify_url==通知位址==接收微信支付非同步通知回呼位址,通知url必須為直接可存取的url,不能攜帶參數。 (這,取個什麼名字好呢。隨便起吧,反正一時半會也用不到)
out_trade_no==商家訂單號==商家系統內部的訂單號碼,32個字元內、可包含字母(每次看完微信的官方解釋就更迷茫了,有木有。沒關係,我就傳個1咋了。)
total_fee==總金額==訂單總金額,單位為分(為了公司的專案測試,還得自己掏銀子,1分錢也是錢啊。ps:這時候總會想起,一個同學說過,蒼蠅腿也是肉啊)openid ==使用者識別==trade_type=JSAPI,此參數必傳,使用者在商家appid下的唯一識別。 還有最重要的一個,重要的角色總是會在最後登場。 sign==簽名==官方給的簽章演算法。 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_3。沒看懂,看不太懂,你覺得你看懂了,沒關係,不遇到幾次簽名錯誤,好意思說自己做過微信支付開發嗎。 說這個sign還有一個更重要的參數。參與簽名的參數。反正我找了好久才找到。 (公司營運申請的微信支付,當我找她要的時候,他的表情是這樣子的。
key==key設定路徑:微信商家平台(pay.weixin.qq.com)- ->帳戶設定-->API安全-->金鑰設定
在這裡:
網路上有說怎麼找得。我也懶得去找。直接自己想了一個字串,然後用MD5加密成32位元的字串,重新設定的。
產生sign簽章的時候,要用到這個key值,所以,要保存好。
我看別人生成簽名(sign)用了很多,反正我就用了上面給出的那些參數生成的sign.(這個上面指的是我的博客上面,不是微信上面。為了減少誤解,貼出我產生sign簽章的參數)
我產生sign簽章的參數
#
##準備好以上參數之後,封裝成XML格式如下:<?xml version="1.0" encoding="UTF-8" standalone="yes"?><xml> <appid>wxb1427ebebexxxxxx</appid> XXX费用 <device_info>WEB</device_info> <mch_id>132186xxxx</mch_id> <nonce_str>6AED000AF86A084F9CB0264161E29DD3</nonce_str> <notify_url>https://一个域名/api/wechatPay/jsapiPayNotify</notify_url> <openid>oo8WUt0taCqjt552htW1vw-xxxxx</openid> <out_trade_no>1</out_trade_no> <sign>各种排序+key生成的那个sign</sign> <total_fee>1</total_fee> <trade_type>JSAPI</trade_type></xml>呼叫微信的統一下單一位址:https://api.mch.weixin.qq.com/pay/unifiedorder#見證奇蹟的時刻。如果以上參數都神奇的對了,那麼會收到微信回傳的XML字串,格式如下
<xml> <return_code></return_code> <return_msg></return_msg> <appid></appid> <mch_id></mch_id> <device_info></device_info> <nonce_str></nonce_str> <sign></sign> <result_code></result_code> <prepay_id></prepay_id> <trade_type></trade_type></xml>
prepay_id 获取到这货之后,第一步骤已经结束了,可以去喝个茶,吃个冰棍,小庆祝一下。 2、H5调起微信支付的内置JS後台傳回前台的參數中,應包含以下幾項:appId==這個是不變的==永遠不變timeStamp==時間戳==規則: https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_2。看完仍是一臉迷茫的,沒關係,我們有工具類。誰知道呢,直接呼叫就好了 nonceStr ==反正我用的跟剛才簽章是同一個隨機字串。理論上不用應該也沒有關係的,勤快的小夥伴可以試試package==訂單詳情擴展字符串==統一下單接口返回的prepay_id參數值,提交格式如:prepay_id=** *(你猜對了。剛才我們費那麼大力氣,得到到的prepay_id就是在這裡用的。第一次使用的時候,一直拿訂單ID去請求,然後微信給我的信息就是請求參數錯誤,缺少參數$key0$.不要告訴我,只有我一個人。重新生成,在後台。使用如上4個參數+一個key(永遠不變)。 (我產生簽章的時間戳記和傳回給前台的時間戳記是timeStamp是同一個。不一樣行不行,木有驗證)產生paySign的程式碼
##NB:產生prepay_id時appid是小寫的i,產生paySign時,appId是大寫的I到此為止如果一切順利,你會看到這樣子的一個頁面。
但是如果,你沒有看到這個。而是提示,目錄未授權,或測試帳號未在白名單中,我覺得,這才是這篇部落格的正確開啟方式呢。
微信公眾號後台,微信支付,開發配置中有一個支付授權目錄,測試授權目錄,
支付授權目錄:開發時,先放一放。 (鄧小平爺爺在對待中日關係時曾經說過,我們解決不了的問題,先放一放。)
測試授權目錄:我們要填寫的就是這個了。要一個外網能存取到的位址。 ip也可以(親測可以的)。如果你的ip,外網不能訪問,找維運同學解決。建議,配置一個測試用的外網可存取的網域名稱。
測試白名單:這個不解釋
輸入密碼,然後,就會看到這樣子的結果。 (這也不需要我們做什麼了) #好激動啊,趕快去吃點東西,抑制一下,內心的激動。剩下的,我們還有兩件事情要做。先說簡單的。
3、支付成功之後跳轉回自己的系統的某個頁面
function onBridgeReady(){ WeixinJSBridge.invoke ( 'getBrandWCPayRequest', { "appId" : appId, //公众号名称,由商户传入 "timeStamp":timeStamp, //时间戳,自1970年以来的秒数 "nonceStr" : nonceStr, //随机串 "package" : Package, "signType" :signType, //微信签名方式: "paySign" : paySign //微信签名 }, function(res){ if(res.err_msg == "get_brand_wcpay_request:ok" ) { window.location.replace("index.html"); } } ); }
上述程式碼中的,紅色部分,修改成你想去的頁面即可。是不是好奇replace是什麼鬼。移步這裡,看一下:http://www.php.cn/
4,最後一部分啦。 fighting
此部分有以下3小步驟
1)解析傳過來的流信息,透過重新簽章的方式驗證流中所包含的資訊的正確性。就是判斷這個訊息到底是不是微信發的
2)return_code和result_code都是SUCCESS的話,處理商家自己的業務邏輯。就是訂單的支付狀態啊等一些資訊。
3)告诉微信,我收到你的返回值了。不用在发了。
关于以上三点的解释。微信官方是这么说的
//支付完成后,微信会把相关支付和用户信息发送到商户设定的通知URL, //验证签名,并回应微信。 //对后台通知交互时,如果微信收到商户的应答不是成功或超时,微信认为通知失败, //微信会通过一定的策略(如30分钟共8次)定期重新发起通知, //尽可能提高通知的成功率,但微信不保证通知最终能成功。 //商户自行增加处理流程, //例如:更新订单状态 //例如:数据库操作 //例如:推送支付完成信息
还记得我们在第一步生成预支付id(prepay_id时的那个notify_url吗。如果不记得了,请往上翻。如果当时只是随便写了一个,那么这会需要去改一改了。)
一个能访问的到的action.同样地址需要外网能访问的到。没有试ip好不好使。开发这部分功能的时候,运维同学已经配置了测试域名。好开心啊,终于不用在纠结于一些交互配置了。
和支付宝不同,微信返回的是流。和支付宝不同,微信返回的是流。和支付宝不同,微信返回的是流。重要的事情说三遍
解析之后,得到的格式是这样子的
<xml><appid><![CDATA[wxb1427ebebeeaxxxx]]></appid> <bank_type><![CDATA[CFT]]></bank_type> <cash_fee><![CDATA[1]]></cash_fee> <device_info><![CDATA[WEB]]></device_info> <fee_type><![CDATA[CNY]]></fee_type> <is_subscribe><![CDATA[Y]]></is_subscribe> <mch_id><![CDATA[132186xxxx]]></mch_id> <nonce_str><![CDATA[07FC15C9D169EE48573EDD749D25945D]]></nonce_str> <openid><![CDATA[oo8WUt0taCqjt552htW1vw-xxxxx]]></openid> <out_trade_no><![CDATA[你的订单编号]]></out_trade_no> <result_code><![CDATA[SUCCESS]]></result_code> <return_code><![CDATA[SUCCESS]]></return_code> <sign><![CDATA[E69940B3EDC437CB5A181210D523806E]]></sign> <time_end><![CDATA[20160621134204]]></time_end> <total_fee>1</total_fee> <trade_type><![CDATA[JSAPI]]></trade_type> <transaction_id><![CDATA[400386200120160621763973xxxx]]></transaction_id> </xml>
对以上第一点和第三点做个解释。
再次吐槽一下。微信真的很喜欢用签名啊。整个过程,3遍签名。也是醉了。
1)我们看到上述微信返回的xml中含有很多字段。使用上述xml中,处sign意外的值+key,进行签名。你没有看错。包含result_code和return_code。
微信的官方对于签名有解释。
原谅我真的好久不学语文了。真的没理解这句话,是用微信回调函数中传的参数,进行重新签名。傻傻的,还在想,用第二次签名是的参数进行签名,时间戳怎么办,要不要存在数据库里面。
将获得的签名与xml中的sign对比,如果相同,证明是微信返回的通知。如果不同,你的通知地址可能被黑客破解了。要不要告诉老板呢,告诉老板了,我怎么解决呢。
2)商户逻辑处理,不解释
3)告诉微信,我收到了你的通知,不需要在发送了。
怎么告诉微信呢。我翻遍了微信的文档,也没有找到回复微信通知这个url。
经人知道,再一次的刷新了认知观。用response.
我是这么写的
response.getWriter().write(xml);
这个xml就是微信给你的那个流转化的字符串。
xml中的return_code要是SUCCESS或者FAIL
别问我怎么知道的。官方的demo里面写的
if($notify->checkSign() == FALSE){ $notify->setReturnParameter("return_code","FAIL");//返回状态码 $notify->setReturnParameter("return_msg","签名失败");//返回信息 }else{ $notify->setReturnParameter("return_code","SUCCESS");//设置返回码 } $returnXml = $notify->returnXml();
按照这个写法,返回的数据。在没有收到微信的通知。
之前在测试的时候,返回字符串之后,在没有收到微信的通知,这两天偶然查日志,发现,微信在一直的,通知,不一定是8次。从打印的日志看
有4次,6次。突然,好晕啊。有明白的朋友,还请多多指教
--------------------------------------------------------------
微信公众号支付--JSAPI的开发思路和一下参数的具体解释,全部完成了。具体代码。等我从公司项目里面抽出来。在整理。
还有一个坑:我们在第一步的时候,body传的是英文,如果传中文,直接能用的赶紧感谢一下上苍,返回参数错误的,应该是正常吧。
我的对象和xml转化是用的Java的JAXBContext。很好用的赶脚。赶脚比XMLStream好用。
更多微信公眾號支付開發全過程相关文章请关注PHP中文网!