欢迎您来到懒之才-站长的分享平台!   学会偷懒,并懒出境界是提高工作效率最有效的方法!
首页 > 经验分享 > 网站运营 > 漫谈微信支付-公共号支付

漫谈微信支付-公共号支付

2018-06-15 700 收藏 0 赞一个 0 真差劲 0 去评论

微信支付.jpeg

本文对微信公共号支付的实现过程进行详细介绍。

概述

公共号支付主要应用于微信内H5页面上发起的微信支付流程,它相对于扫码支付和APP要复杂一些,而且在实际开发过程中遇到的问题相对较多。


实现过程

公共号支付与APP支付类似,都需要调起统一下单接口获得prepay_id,根据prepay_id等参数调起微信发起支付流程,最后微信后台将支付结果异步回调给商户后台。

◆ 准备工作
公共号支付需要提前在微信公共平台进行业务配置,包括设置支付授权目录、设置JS接口安全域名以及设置授权回调页面域名。

支付授权目录:

位置:微信支付——>开发配置——>公共号支付

[1] 所有使用公众号支付方式发起支付请求的链接地址,都必须在支付授权目录之下;

[2] 正式支付授权目录最多设置3个,测试授权目录最多设置1个,且域名必须通过ICP备案;

[3] 头部要包含http或https,须细化到二级或三级目录,以左斜杠“/”结尾。

业务中发起支付的页面地址必须在授权目录下,否则调用下单接口时会提示“当前页面的URL未注册”。


JS接口安全域名:

位置:微信支付——>公共号设置——>功能设置——>JS接口安全域名

设置JS接口安全域名后,公众号开发者可在该域名下调用微信开放的JS接口。


注意事项:

[1] 可填写三个域名,要求是一级或一级以上域名(例:qq.com,或者 www.qq.com ),需使用字母、数字及“-”的组合,不支持IP地址及端口号;

[2] 填写的域名须通过ICP备案的验证;

[3] 一个自然月内最多可修改并保存三次。


授权回调页面域名:

位置:微信支付——>接口权限——>网页授权获取用户基本信息

用户在网页授权页同意授权给公众号后,微信会将授权数据传给一个回调页面,回调页面需在此域名下,以确保安全可靠。


注意事项:

[1] 回调页面域名需使用字母、数字及“-”的组合,不支持IP地址及端口号。填写的域名需与实际回调URL中的域名相同;

[2] 填写的域名须通过ICP备案的验证。

获取用户授权时redirect_uri对应的URL必须在此域名下,否则回调的地址会无法打开。


◆ 统一下单

公共号支付统一下单接口需要传递openid参数,微信公共平台对于openid的解释如下:

在关注者与公众号产生消息交互后,公众号可获得关注者的OpenID(加密后的微信号,每个用户对每个公众号的OpenID是唯一的。对于不同公众号,同一用户的openid不同)。

公众号可根据以下接口来获取用户的openid,如需获取用户的昵称、头像、性别、所在城市、语言和关注时间,则需要用户授权。

参考信息:http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html
开发者如果需要将同一个用户在不同公众号下的openid统一为一个id来记录,可以参考以下接口:
参考信息:http://mp.weixin.qq.com/wiki/14/bb5031008f1494a59c6f71fa0f319c66.html
即openid其实是每个用户在不同公共号内的唯一标示,获取openid需要先经过用户同意授权,获取code,再通过code获取openid。


◆ 获取用户授权

微信提供了两种授权方式:snsapi_base和snsapi_userinfo。

snsapi_base:不弹出授权页面,直接跳转,只能获取用户openid;

snsapi_userinfo:弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息。

想要获取code,需要构造如下地址:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

其中SCOPE参数为snsapi_base或snsapi_userinfo,REDIRECT_URI为获取用户授权后跳转的地址。
此处需要在微信公共平台配置授权回调页面域名:微信公共平台——>接口权限——>网页授权获取用户基本信息,点击“修改”,在弹出的页面中填写授权回调页面域名,REDIRECT_URI所在的域名要与填写的回调页面域名相同,否则在进行用户授权时会提示redirect_uri错误。

获取code后,再请求以下链接获取openid:
https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

其中APPID为公共号唯一标示,SECRET为公共号APPSECRET。

有关如何获取用户openid的详细内容可以参考微信官网文档网页授权获取用户基本信息(PS:以上这是最新版的公共号开发文档,这是旧版的文档,建议查看新版文档)

微信公共号支付SDK文件JsApiPay类提供了获取用户openid的方法GetOpenid:

/**
   * 
   * 通过跳转获取用户的openid,跳转流程如下:
   * 1、设置自己需要调回的url及其其他参数,跳转到微信服务器https://open.weixin.qq.com/connect/oauth2/authorize
   * 2、微信服务处理完成之后会跳转回用户redirect_uri地址,此时会带上一些参数,如:code
   * 
   * @return 用户的openid
   */
  public function GetOpenid()
{
    //通过code获得openid
    if (!isset($_GET['code'])){
      //触发微信返回code码
      $baseUrl = urlencode('http://'.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'].$_SERVER['QUERY_STRING']);
      $url = $this->__CreateOauthUrlForCode($baseUrl);
      Header("Location: $url");
      exit();
    } else {
      //使用code码,以获取openid
        $code = $_GET['code'];
      $openid = $this->getOpenidFromMp($code);
      return $openid;
    }
  }

其中GetOpenidFromMp方法在官方SDK中存在错误,CURLOPT_TIMEOUT写错了:

/**
   * 
   * 通过code从工作平台获取openid机器access_token
   * @param string $code 微信跳转回来带上的code
   * @return openid
   */
  public function GetOpenidFromMp($code)
{
    $url = $this->__CreateOauthUrlForOpenid($code);
    //初始化curl
    $ch = curl_init();
    //设置超时
    //curl_setopt($ch, CURLOP_TIMEOUT, 30);		//CURLOP_TIMEOUT写错了!!!!应该是CURLOPT_TIMEOUT
    curl_setopt($ch, CURLOPT_TIMEOUT, 30);
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,FALSE);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST,FALSE);
    curl_setopt($ch, CURLOPT_HEADER, FALSE);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
    if(WxPayConfig::CURL_PROXY_HOST != "0.0.0.0" 
      && WxPayConfig::CURL_PROXY_PORT != 0){
      curl_setopt($ch,CURLOPT_PROXY, WxPayConfig::CURL_PROXY_HOST);
      curl_setopt($ch,CURLOPT_PROXYPORT, WxPayConfig::CURL_PROXY_PORT);
    }
    //运行curl,结果以json形式返回
    $res = curl_exec($ch);
    curl_close($ch);
    //取出openid
    $data = json_decode($res,true);
    $this->data = $data;
    $openid = $data['openid'];
    return $openid;
  }

获取openid后就可以调用统一下单接口获得prepay_id。


◆H5调起微信支付

网页端调起支付API提供了前端调起微信发起支付的方法,此处需要特别注意:公共号支付调起微信支付的接口参数与APP支付调起微信支付的参数大小写不同!

APP拉起微信支付接口参数列表:

APP-拉起微信支付.png

APP拉起微信支付

公共号拉起微信支付接口参数列表:

公共号拉起微信支付.png

公共号拉起微信支付

可以发现变量名一列,公共号接口有的字母是大写的,生成签名是需要区分参数大小写的,所以这块一定要注意,否则在调用接口时你就会一直收到签名错误的提示。

签名生成成功了,但是在调用调起微信支付接口时你可能会收到提示”调用支付JSAPI缺少参数:timeStamp,但是明明已经传递该参数了,怎么还会提示缺少参数呢?是由timeStamp的类型引起的,上图的参数列表中timeStamp类型为String字符串类型,很多时候我们程序里直接使用time()生成时间戳是整数,因此在将timeStamp传递给该接口时需要转换为字符串类型。

如果是服务器端调用拉起微信支付接口,需要将WxPay.Data.php文件中WxPayJsApiPay的SetTimeStamp方法作相应修改:

/**
  * 设置支付时间戳
  * @param string $value 
  **/
  public function SetTimeStamp($value)
{
    //modify by yuri 2016/7/5 解决JSAPI微信支付提示“缺少timeStamp参数”问题
    $this->values['timeStamp'] = (string)$value;
  }

测试开发时配置好测试授权目录,将微信号添加到测试白名单,H5调用拉起微信支付接口即可完成支付。

常见问题

◆支付场景非法

支付场景非法.png

错误场景:前端调用拉起微信支付接口getBrandWCPayRequest报错。

原因分析:与开发用的APPID有关。JSAPI支付用到的APPID是从微信公告平台申请,APP支付用到的APPID是从微信开放平台申请,如果将APP支付的APPID用于JSAPI支付,就会收到该错误提示。
解决方法:不同的支付场景要使用相对应的APPID,不允许跨场景使用APPID支付。

◆您没有JSAPI支付权限

错误场景:后台调用unifiedorder统一下单接口报错。

原因分析:同“支付场景非法”

解决方法:同“支付场景非法”

◆不允许跨号支付

不允许跨号支付.png

错误场景:在公共号内调用unifiedorder统一下单接口报错。

原因分析:公共号A申请开通了JSAPI支付,得到该公共号微信支付开发对应的APPID、KEY、APPSECRET,如果在公共号B内调用公共号A开发的微信支付接口,就会提示“不允许跨号支付”,微信侧限制了微信支付开发的相关接口只能在对应的公共号内调用。

解决方法:在微信JSAPI开发中配置的公共号内调用微信支付相关接口。


◆缺少openid

缺少openid.png

错误场景:后台调用unifiedorder统一下单接口报错。
原因分析:公共号支付的下单接口需要传递openid参数,为用户在商户appid下的唯一标识。调用统一下单接口时需要先获取用户openid。

解决方法:调用unifiedorder统一下单接口前,确保已经获取到用户openid。


◆缺少timeStamp

缺少timeStamp.png

错误场景:前端调用拉起微信支付接口getBrandWCPayRequest报错。

原因分析:getBrandWCPayRequest参数列表中写明了timeStamp参数类型为String,如果传递的timeStamp值为整型,会产生该错误。

解决方法:将timeStamp的值显示转换为字符串类型。


◆签名失败

签名失败.png

错误场景:前端调用拉起微信支付接口getBrandWCPayRequest报错。

原因分析:公共号支付拉起微信支付接口与APP支付拉起微信支付接口中参数的大小写不同,生成签名会区分大小写。

解决方法:生成签名要严格按照参数列表中变量名称进行生成,尤其注意参数大小写。


◆body参数长度有误

body参数长度有误.png

错误场景:后台调用unifiedorder统一下单接口报错。

原因分析:body参数长度太长,unifiedorder统一下单接口中body参数长度为String(128),即占用128个字节,一个汉字占用3个字节,一个字母或数字占用1个字节,所以如果全部为汉字的话,最多42个。

解决方法:必要时使用字符串截取函数限制body的长度。


◆URL未注册

URL未注册.png

错误场景:前端调用拉起微信支付接口getBrandWCPayRequest报错。

原因分析:授权目录配置问题,当前支付页与授权目录设置不匹配。

解决方法:详细解决方案可参考另一篇博文<漫谈微信支付-授权目录设置>


◆下单账号与支付账号不一致

下单账号与支付账号不一致.png

错误场景:前端调用拉起微信支付接口getBrandWCPayRequest报错。前端调用拉起微信支付接口getBrandWCPayRequest,拉起微信账号A,但是在微信A中没有完成支付(例如:执行了取消操作),此时如果换另一个微信账号B,再对微信端同一个订单进行支付,拉起微信,此时会报该错

原因分析:微信端同一个订单号,限制了下单与支付账号必须使用同一个微信。在调用下单接口时传递了openid,在调用拉起微信支付接口时,如果当前用户的微信与下单微信不同,就会报该错。

解决方法:下单账号与支付账号必须使用同一个微信。


◆商户订单号重复

商户订单号重复.png

错误场景:后台调用unifiedorder统一下单接口报错。

原因分析:同一个订单,如果修改了商品描述或者商品价格,再用同一个订单号去调用统一下单接口就会报该错。

解决方法:重新生成订单。


◆订单已过期

订单已过期.png

错误场景:后台调用unifiedorder统一下单接口报错。

原因分析:下单有时效性。

解决方法:重新下单。


◆调用微信支付相关接口异常缓慢

微信支付SDK中所有最终请求微信服务器的出口均是经过WxPay.Api.php中的postXmlCurl接口:

/**
   * 以post方式提交xml到对应的接口url
   * @param string $xml  需要post的xml数据
   * @param string $url  url
   * @param bool $useCert 是否需要证书,默认不需要
   * @param int $second   url执行超时时间,默认30s
   * @throws WxPayException
   */
  private static function postXmlCurl($xml, $url, $useCert = false, $second = 30)
{
    $ch = curl_init();
    //设置超时
    curl_setopt($ch, CURLOPT_TIMEOUT, $second);
    //如果有配置代理这里就设置代理
    if(WxPayConfig::CURL_PROXY_HOST != "0.0.0.0" 
      && WxPayConfig::CURL_PROXY_PORT != 0){
      curl_setopt($ch,CURLOPT_PROXY, WxPayConfig::CURL_PROXY_HOST);
      curl_setopt($ch,CURLOPT_PROXYPORT, WxPayConfig::CURL_PROXY_PORT);
    }
    curl_setopt($ch,CURLOPT_URL, $url);
    curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);
    curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,FALSE);
    //设置header
    curl_setopt($ch, CURLOPT_HEADER, FALSE);
    //要求结果为字符串且输出到屏幕上
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
    //modify by yuri 2016/7/5 设置curl默认访问IPv4网络
    curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
    if($useCert == true){
      //设置证书
      //使用证书:cert 与 key 分别属于两个.pem文件
      curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
      curl_setopt($ch,CURLOPT_SSLCERT, WxPayConfig::SSLCERT_PATH);
      curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
      curl_setopt($ch,CURLOPT_SSLKEY, WxPayConfig::SSLKEY_PATH);
    }
    //post提交方式
    curl_setopt($ch, CURLOPT_POST, TRUE);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
    //运行curl
    $data = curl_exec($ch);
    //返回结果
    if($data){
      curl_close($ch);
      return $data;
    } else { 
      $error = curl_errno($ch);
      curl_close($ch);
      throw new WxPayException("curl出错,错误码:$error");
    }
  }

因为CURL默认先解析IPV6,再解析IPV4,所以如果你的支付场景只有IPV4网络,则最好设置CURL默认访问IPV4,这样可以省去解析IPV6的时间,接口调用速度明显加快。

一、推荐使用迅雷或快车等多线程下载软件下载本站资源。

二、未登录会员无法下载,登录后可获得更多便利功能,若未注册,请先注册。

三、如果服务器暂不能下载请稍后重试!总是不能下载,请点我报错 ,谢谢合作!

四、本站大部分资源是网上搜集或私下交流学习之用,任何涉及商业盈利目的均不得使用,否则产生的一切后果将由您自己承担!本站将不对任何资源负法律责任.如果您发现本站有部分资源侵害了您的权益,请速与我们联系,我们将尽快处理.

五、如有其他问题,请加网站设计交流群(点击这里查看交流群 )进行交流。

六、如需转载本站资源,请注明转载来自并附带链接

七、本站部分资源为加密压缩文件,统一解压密码为:www.aizhanzhe.com

大家评论