这几年国内互联网的迅速发展不仅催生出了BAT,也使得第三方支付平台异军突起。在欧美还是信用卡统治的时代,另一个具有中国特色的第三方支付方式(External Payments, 或跳转支付)不仅成功的绑定了用户的支付习惯,更是为国外支付行业进入中国建造了一个壁垒。而支付宝(Alipay)微信(WeChat)则是如今第三方支付的主流。

最近在做微信支付接入的项目,虽然有微信文档以及那边技术人员的帮助,在调试签名上还是走了不少弯路。就当是个记录,也给将要接入者提供一个参考。

微信APP支付接口签名

  • 基本参数格式要求
    参数中间如果有空格需要自行URL编码;参数中涉及到金额的一律转换成以分为单位的整数,不允许出现小数点。请确保相应的秘钥对和AppID是没问题的。
  • 获取PrepayId请求签名:
    1. 把请求转换成JSON串格式POST方式发出,如果使用GSON库的GsonBuilder来transform,则需要使用disableHtmlEscaping().
    2. 对请求串中的package参数进行MD5签名时,traceid参数即使为空,也需要加入签名串。
    3. MD5秘钥也需要参加queryString形式的排序。所有参数名均要转成小写,参数值中间不能有空格。
    4. package值转换成URLEncoded的值后作为整体Prepareid请求的一个参数,在和其他值一起参与SHA1签名。如果是单纯的MD5+SHA1签名,则SHA1签名不需要转换成大写。但如果接入商户想用RSA签名来代替SHA1签名,则需要注意:
      • 微信后台使用的是C++版本的签名接口,虽然微信文档上会写SHA1保持不变,其结果封装成RSA即可,但此处所指的RSA签名是纯粹的没有经过哈希的RSA签名。而我们通畅所指的RSA签名则大多数时候是指SHA1_WITH_RSA。所以如果你RSA签名出错,你可以看下是否是自己多了一层SHA1哈希。
    5. timestamp 是以秒为单位,而非默认的毫秒。
  • 支付成功后台通知签名:
    1. 其POST体采用XML格式来返回通知结果。值得注意的是,XML格式可能包含<![CDATA[]]格式的数据,即Character Data。其表明在XML标签之间可能含有不能被XML 标记语言准确解析的字符,因此需要用这个标记。在验签提取字符串的时候,需要去掉该字符。下面则是提取含有CDATA的XML数据一段小代码:
  private String getNodeDataFromNode(Node node) {
      String data;
      if(node == null) {
        return null;
      }
      if(node instanceof CharacterData) {
        data = ((CharacterData) node).getData();
      }
      else {
        data = node.getNodeValue();
      }
      return data;
    }
  
  

财付通退款接口签名

财付通相对于微信的支付系统比较老久,很多文档似乎没有微信写的严密,列出了一些可能让读者混淆的地方。

  • 退款请求原生支持MD5和RSA签名,字符集也说是可以支持UTF-8和GBK。但其实有些时候,即使你请求串中声明是UTF-8,一些签名错误的情况下,财付通返回的信息仍有可能是GBK的,所以在处理签名响应的时候这个需要注意一下。
  • 退款请求文档中虽然说明是可以支持GET和POST请求,但是不要被他误解。尤其当你使用POST请求时,你还是要把请求体转换成query string格式,且POST体中的参数也要用URLEncode格式。
  • 而与此相反,退款响应采用的是XML格式的响应体,不需要URLDecode了。

常见调试签名错误描述

  • not match signature {"errcode":49004,"errmsg":"not match signature"}
  • 签名错误
  • invalid signature
  • service is busy, please try later.
  • 签名验证失败

后续想到继续添加吧.
So long, and thanks for all the fish.

参考

[1]. 微信签名安全规范.
[2]. 财付通支付.
[3]. Z.