当前位置: 首页 > news >正文

微信支付JSAPI,实测!终极方案

在用JSAPI开发微信支付的时候,遇到了很多坑,我也对朋友说过,一步一坑。最后终于算是走出来了。期间翻阅过很多网友写的教程,但是都不实用,JAVA,Python都有看过,大多数都是复制粘贴,倍感失望。

开发环境

thinkphp5.0 php

(开始使用JSAPI需要一个概念,就是在整个JSAPI的逻辑里面,只存在一个随机字符串 和一个 时间戳。相当于JSAPI类里的全局。)

注意:由于我这里用的http_build_query()body里面的中文会被格式化,所以这里先建议body使用非中文,至于中文解决,可以用正则去替换,或者不用http_build_query()

开始开发

全局初始化

 public function __construct($total_fee, $body, $openid)
    {
        $rand = rand(11, 99);
        $mp_info = get_mpid_info();//获取微信信息
        $this->appid = $mp_info['appid'];
        $this->nonce_str = nonceStr(32);
        $this->spbill_create_ip = Request::instance()->ip();
        $this->mch_id = $mp_info['mch_id'];
        $this->key = $mp_info['paykey'];
        $this->timestamp = time();
        $this->sign;//一次签名
        $this->total_fee = $total_fee;
        $this->out_trade_no = time() . $rand;
        $this->notify_url = 'http://uedream.cn/index.php';
        $this->body = $body;
        $this->openid = $openid;
        $this->sign_type = 'MD5';
        $this->createsign(); //生成签名方法,需要结合createsign方法
    }

以上是初始化签名结构体

获取签名

文档: https://pay.weixin.qq.com/wik...
public function createsign()
    {
        $build = [
            'appid' => $this->appid,
            'body' => $this->body,
            'mch_id' => $this->mch_id,
            'nonce_str' => $this->nonce_str,
            'notify_url' => $this->notify_url,
            'openid' => $this->openid,
            'out_trade_no' => $this->out_trade_no,
            'sign_type' => $this->sign_type,
            'spbill_create_ip' => $this->spbill_create_ip,
            'timeStamp' => $this->timestamp,
            'total_fee' => $this->total_fee,
            'trade_type' => $this->trade_type,
            'key' => $this->key,
        ];
        $string = http_build_query($build);
        $string = str_replace('%2F', '/', $string); //格式化网址
        $string = str_replace('%3A', ':', $string); //格式化网址
        $md5 = md5($string);
        $this->sign = strtoupper($md5);
    }

统一下单

文档: https://pay.weixin.qq.com/wik...
 public function unifiedorder()
    {

        $data = [
            'appid' => $this->appid,
            'body' => $this->body,
            'mch_id' => $this->mch_id,
            'nonce_str' => $this->nonce_str,
            'notify_url' => $this->notify_url,
            'openid' => $this->openid,
            'out_trade_no' => $this->out_trade_no,
            'sign' => $this->sign,
            'sign_type' => 'MD5',
            'spbill_create_ip' => $this->spbill_create_ip,
            'timeStamp' => $this->timestamp,
            'total_fee' => $this->total_fee * 1,
            'trade_type' => $this->trade_type,
        ];
        $xml = arrayToXml($data);
        $result = http_post(self::UNIFIEDORDER, $xml);
        $return = xmlToArray($result);
        $this->package = 'prepay_id=' . $return['prepay_id'];
        $this->renCreatesign();//这是二次签名。文档里面我是没有看到,反正我是卡到这里了。
        $returns = [
            'appid' => $this->appid,
            'noncestr' => $this->nonce_str,
            'signtype' => $this->sign_type,
            'package' => $this->package,
            'sign' => $this->resign,
            'timestamp' => $this->timestamp,
        ];
        return $returns;
    }

统一下单请忽略的所有的回调参数,只要prepay_id,其它的参数暂时看做障眼法,获取到了统一下单,还需要进行二次签名,上面代码里面有一个$this->renCreatesign(),就是调用的二次签名方法

二次签名

文档: https://pay.weixin.qq.com/wik...

所谓的二次签名就是,appId,nonceStr,package,signType,timeStamp,key的加密。一样的签名方式,可以参考签名文档,进行签名。(上面参数已经按照ASCII进行排序,大小写也请按照给出的进行加密)
注意: package格式为prepay_id=xxxxxxxxxxxx。xxxx部分为统一下单获取的prepay_id

代码参考:

public function renCreatesign()
    {
        $build_data = [
            'appId' => $this->appid,
            'nonceStr' => $this->nonce_str,
            'package' => $this->package,
            'signType' => $this->sign_type,
            'timeStamp' => $this->timestamp,
            'key' => $this->key,
        ];
        $result = http_build_query($build_data);
        $put_data = str_replace('%3D', '=', $result); //格式化网址
        $signatrue = md5($put_data);

        $this->resign = strtoupper($signatrue);

    }

至此,所有的签名应经完成,控制器使用unifiedorder()进行参数获取。

前端

这里开始使用jsapi做支付动作

            WeixinJSBridge.invoke(
                "getBrandWCPayRequest",
                {
                  appId: res.appid, //公众号名称,由商户传入
                  timeStamp: res.timeStamp, //时间戳,自1970年以来的秒数
                  nonceStr: res.nonce_str, //随机串
                  package: res.package,
                  signType: res.signType, //微信签名方式:
                  paySign: res.sign //微信签名
                },
                function(res) {
                  alert(JSON.stringify(res));
                  if (res.err_msg == "get_brand_wcpay_request:ok") {
                    // 使用以上方式判断前端返回,微信团队郑重提示:
                    //res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
                  }
                }
              );

前端所有需要调用的参数均在unifiedorder()可以获取到。

这里提一下WeixinJSBridge.invokewx.chooseWXPay 的区别。WeixinJSBridge.invoke可以不用引用weixinjs便可使用,也不需要config。在安卓手机上也能回调出错误信息。wx.chooseWXPay需要引用weixinjs,也需要使用config,而且在安卓手机上面的提示特别不友好。

结语

微信支付文档说实话真的很坑 很坑。貌似写文档的小哥这天情绪不好。写出来的让人也感觉到了情绪不好。以上为本人切身操作写出的教程。如还有补充的地方可以随时留言评论。

彩蛋

文档: https://github.com/datalinkag...

下载地址:

composer require datalinkage/wxpay

相关文章:

  • 【转载】关于nginx以及内核参数的配置
  • Material Design设计规范在ComponentOne For WinForm的应用(上)
  • 从数据中心基础设施的视角来看 Facebook 机器学习的应用
  • 073:【Django数据库】ORM聚合函数详解-Count
  • 2019年如何成为全栈工程师?
  • 原生 js 实现移动端 Touch 滑动反弹
  • 文章正在审核中 为什么使用了爬虫代理ip,真实IP还是被封禁了?
  • elasticsearch-head插件安装
  • Git 常用命令
  • [转]Introduction of iSCSI Target in Windows Server 2012
  • 【转】理解红黑树
  • FastDFS-图片服务器
  • Volo.Abp.EntityFrameworkCore.MySQL 使用
  • Future 和 FutureTask 源码详解
  • redis requires ruby version 2.2.2的解决方案
  • hexo+github搭建个人博客
  • git 常用命令
  • java取消线程实例
  • JS基础之数据类型、对象、原型、原型链、继承
  • js写一个简单的选项卡
  • PAT A1120
  • php中curl和soap方式请求服务超时问题
  • react-core-image-upload 一款轻量级图片上传裁剪插件
  • Redis 中的布隆过滤器
  • swift基础之_对象 实例方法 对象方法。
  • 阿里云ubuntu14.04 Nginx反向代理Nodejs
  • 第十八天-企业应用架构模式-基本模式
  • 浮现式设计
  • 日剧·日综资源集合(建议收藏)
  • 学习JavaScript数据结构与算法 — 树
  • 自定义函数
  • 资深实践篇 | 基于Kubernetes 1.61的Kubernetes Scheduler 调度详解 ...
  • ​人工智能之父图灵诞辰纪念日,一起来看最受读者欢迎的AI技术好书
  • ###51单片机学习(2)-----如何通过C语言运用延时函数设计LED流水灯
  • (AtCoder Beginner Contest 340) -- F - S = 1 -- 题解
  • (附源码)springboot家庭财务分析系统 毕业设计641323
  • (一)硬件制作--从零开始自制linux掌上电脑(F1C200S) <嵌入式项目>
  • (转)JVM内存分配 -Xms128m -Xmx512m -XX:PermSize=128m -XX:MaxPermSize=512m
  • (轉貼) 蒼井そら挑戰筋肉擂台 (Misc)
  • .Net MVC4 上传大文件,并保存表单
  • .NET MVC第五章、模型绑定获取表单数据
  • .NET 设计模式—适配器模式(Adapter Pattern)
  • .NET4.0并行计算技术基础(1)
  • .Net6支持的操作系统版本(.net8已来,你还在用.netframework4.5吗)
  • .net打印*三角形
  • .Net的C#语言取月份数值对应的MonthName值
  • .NET开源全面方便的第三方登录组件集合 - MrHuo.OAuth
  • .net与java建立WebService再互相调用
  • .skip() 和 .only() 的使用
  • :=
  • @angular/cli项目构建--http(2)
  • @cacheable 是否缓存成功_让我们来学习学习SpringCache分布式缓存,为什么用?
  • @RestController注解的使用
  • []error LNK2001: unresolved external symbol _m
  • [AIGC codze] Kafka 的 rebalance 机制