沒太多坑的微信支付

fairjm發表於2015-12-10

公眾號支付還沒做完....但已經調通 接下來似乎會要做掃碼支付之類的...
但總體感覺坑數量不是很多 比支付寶的痛感要少一點 所以先寫一寫 支付寶那個iOS網頁支付不返回資料只返回狀態碼 android網頁支付都返回的坑實在太痛苦了... ...
可見: http://www.ituring.com.cn/article/205821

總的文件在這裡:
https://pay.weixin.qq.com/wiki/doc/api/index.html

要注意做第三方(微信外)的支付要用開放平臺(open)
而微信內的公眾號支付是公眾平臺(mp)
不要用open的賬號去弄mp了。。。 沒用

做app沒遇到什麼坑...感覺很順利
app的文件在這裡:
https://pay.weixin.qq.com/wiki/doc/api/app.php?chapter=9_1

公眾號和app支付流程總體是一樣的:
首先伺服器請求統一下單介面 拿到prepay_id
生成支付請求需要的資料給app
app拿到資料後直接用SDK進行付款
付完款後呼叫一下伺服器的查詢介面 讓伺服器去微信查下訂單狀態(雖然有非同步通知 但為了保險還是讓app主動觸發查詢伺服器上的查詢介面....其實主要是因為內網不可能收到微信的非同步推送 為了內網測試順利這個也是必要的..)

按照文件做的就行
中間涉及很多xml的操作...用xstream寫了個使用起來很簡便的工具類 可以簡單用用
程式碼如下:

    /**
     * @author fairjm
     *
    **/
    public class XmlMapUtil {

        private static final MapConverter MAP_ENTRY_CONVERTER = new MapConverter();

        private static final String NODE_START = "<%s>";

        private static final String NODE_END = "</%s>";

        private static final String VALUE_WITH_CDATA = "<![CDATA[%s]]>";

        private static final String DEFALUT_ROOT_NAME = "xml";

        public static String toXml(final Map<String, String> map, String rootName,
                final boolean withCData) {
            rootName = StringUtils.isBlank(rootName) ? DEFALUT_ROOT_NAME : rootName;
            final StringBuilder sb = new StringBuilder();
            sb.append(String.format(NODE_START, rootName));

            if (map != null) {
                for (final Entry<String, String> entry : map.entrySet()) {
                    sb.append(String.format(NODE_START, entry.getKey()));
                    sb.append(
                            withCData ? String.format(VALUE_WITH_CDATA, entry.getValue()) : entry.getValue());
                    sb.append(String.format(NODE_END, entry.getKey()));
                }
            }

            sb.append(String.format(NODE_END, rootName));
            return sb.toString();
        }

        public static Map<String, String> fromXml(final String xml, final String rootName) {
            Map<String, String> map = null;
            try {
                final XStream xStream = new XStream();
                xStream.alias(rootName, Map.class);
                xStream.registerConverter(MAP_ENTRY_CONVERTER);
                map = (Map<String, String>) xStream.fromXML(xml);
            } catch (final Exception e) {
                e.printStackTrace();
            }
            return map;
        }

        public static class MapConverter implements Converter {
            @Override
            public boolean canConvert(final Class clazz) {
                return Map.class.isAssignableFrom(clazz);
            }
            @Override
            public void marshal(final Object value, final HierarchicalStreamWriter writer, final MarshallingContext context) {
                @SuppressWarnings("unchecked")
                final
                Map<String, String> map = (Map<String, String>) value;
                for (final Entry<String, String> entry : map.entrySet()) {
                    writer.startNode(entry.getKey().toString());
                    final Object val = entry.getValue();
                    if (null != val) {
                        writer.setValue(val.toString());
                    }
                    writer.endNode();
                }

            }

            @Override
            public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) {
                final Map<String, String> map = new HashMap<String, String>();
                while (reader.hasMoreChildren()) {
                    reader.moveDown();
                    final String key = reader.getNodeName();
                    final String value = reader.getValue();
                    map.put(key, value);
                    reader.moveUp();
                }
                return map;
            }
        }

    }

沒啥痛感就不多寫了...


接下來是公眾號的
文件在這裡:
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1

首先要配好JS SDK使用所需的ticket之類的 這個前期在做微信的分享之類的就做好了..這裡也沒打算多說
統一下單和app類似
但是OpenId這個引數是必要的
為了拿到這個引數 要呼叫snsapi_base的微信服務
文件在這裡:
http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html

實現起來也很簡單 這裡不多解釋
將支付引數發給前臺 讓前臺呼叫JS SDK和app也差不多...不過引數名在app那邊是小寫加下劃線 在公眾號裡是駝峰。。可見這個是兩個團隊做的吧。。風格都不一樣。。。

在配置支付授權目錄的時候...我發現他只對配置的那個目錄下的path有效 對於子目錄的path無效...
簡單點說 你配置了 /a/b 那他對 /a/b/1之類的是有效的 但是對於 /a/b/1/2這樣的則會提示URL未配置...當時還以為這個目錄是可以包括子目錄裡的..實在是太天真。。。

其實麻煩的是除錯....但配合fiddler將手機代理到本機可以訪問到本機伺服器加自己改host讓本地地址變為伺服器域名(JS JDK呼叫有域名限制 以及支付授權目錄的限制..) 除錯就變得簡單一點了
這個網上可以搜到 我這裡就不多說了(懶得搜的看這裡: http://www.yyyweb.com/2782.html)

在操作中遇到一些問題 基本都是自己的鍋。。

  • 以為app和公眾號用的appId等是同一個..直接複製過來了用
  • 把APP裡的引數移動過來改 一些引數在計算簽名的時候大小寫忘記改了 但實際返回的結果是正確的 導致簽名錯誤...
  • 本地配置了 兩個host對應外網兩個域名 比如 wap.xxx.com 和 www.xxx.com 外網有nginx做轉發 但自己本地沒有 導致在wap.xxx.com登入了 但是www.xxx.com沒有登入
    在wap.xxx.com通過跳轉(跳了兩次 微信跳到我設定的www.xx.com/weixin/snsbase?code=xx&redirect=wap.xxx.com(業務頁面) 在這個頁面拿到openId後 我自己再跳到redirect的地址) 介面後拿到了openId 但是因為www.xx.com沒有登入..所以session使用者變為null 這個糾結了一段時間...
  • 不知道只有子目錄可以 用了子目錄的子目錄配置授權目錄 弄了一會兒URL未配置...的異常

相關文章