微信JSAPI支付,微信浏览器内支付,解决微信H5支付只能在微信外浏览器支付的问题

2023-05-16

一、设置支付目录

请确保实际支付时的请求目录与后台配置的目录一致(现在已经支持配置根目录,配置后有一定的生效时间,一般5分钟内生效),否则将无法成功唤起微信支付。

在微信商户平台(pay.weixin.qq.com)设置您的JSAPI支付支付目录,设置路径:商户平台–>产品中心–>开发配置,如图7.7所示。JSAPI支付在请求支付的时候会校验请求来源是否有在商户平台做了配置,所以必须确保支付目录已经正确的被配置,否则将验证失败,请求支付不成功。

在这里插入图片描述

二、设置授权域名

开发JSAPI支付时,在统一下单接口中要求必传用户openid,而获取openid则需要您在公众平台设置获取openid的域名,只有被设置过的域名才是一个有效的获取openid的域名,否则将获取失败。具体界面如图7.8所示:
在这里插入图片描述
在这里插入图片描述

三.将支付页面的连接编码后替换连接中的redirect-url参数,获取code

参考链接(请在微信客户端中打开此链接体验)
Scope为snsapi_base ,此连接为静默获取用户授权

https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx520c15f417810387&redirect_uri=http%3A%2F%2Fchong.qq.com%2Fphp%2Findex.php%3Fd%3D%26c%3DwxAdapter%26m%3DmobileDeal%26showwxpaytitle%3D1%26vb2ctag%3D4_2030_5_1194_60&response_type=code&scope=snsapi_base&state=123#wechat_redirect

四.通过code获取openid,有openid后就可以调用统一下单接口了,此时secret不能忽略,在微信公众平台获取

https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

五.调用统一下单接口,AppID等敏感信息我封装到实体类中了

 /**
     * 微信内浏览器支付
     *
     * @return
     */
    @PostMapping("/createJSAPI")
    @ApiOperation("微信内支付,orderId订单ID,openId用户唯一识别ID")
    public DzResult createJSAPI(String orderId, String openId) throws Exception {
        if (StringUtils.isBlank(orderId) || StringUtils.isBlank(openId)) {
            System.out.println("微信内支付空订单号-------------------->");
            return new DzResult().error(OrderCode.ERROR_PARAMS, "参数错误");
        }
        // 获取当前用户
        Claims claims = (Claims) request.getAttribute("authInfo");
        if (claims == null) {
            return new DzResult().error(OrderCode.NOT_LEGAL, "非法操作");
        }
        // 调用业务层查询订单信息
        CyOrder order = weixinPayService.findOrderByOrderId(orderId);
        if (order == null) {
            return new DzResult().error(OrderCode.ORDER_NOT_EXIST, "订单不存在");
        }
        if (!claims.getId().equals(order.getFrontUserId())) {
            return new DzResult().error(OrderCode.NOT_BELONG, "订单不属于当前用户");
        }
        // 商户订单号(用下划线后面数字为标识1:支付定金 2:支付尾款)
        BigDecimal totalAmount;
        // 将数据库价格去分
        BigDecimal mun = BigDecimal.valueOf(100);
        // 名称
        String subject;
        //设置商品详情参数
        HashMap<String, String> attach = new HashMap<>(16);
        // 订单号
        String outTradeNo = orderId;
        //订单号
        attach.put("outTradeNo", outTradeNo);
        //自定义参数
        String attachStr;
        //全款
        //微信是按分为单位,此处*100去分:
        totalAmount = order.getPayMoney().multiply(mun);
        subject = "呈衣全款支付";
        attach.put("subject", subject);
        //去掉小数点后的零
        attach.put("totalAmount", totalAmount.stripTrailingZeros().toPlainString());
        attachStr = JSONUtils.toJSONString(attach);
        Map map = weixinPayService.createJSAPI(outTradeNo, totalAmount.stripTrailingZeros().toPlainString(), attachStr, openId);
        if (map == null) {
            return new DzResult().error(OrderCode.ORDER_WECAT_ERROR, "微信支付异常");
        }
        if ("FAIL".equals(map.get("return_code"))) {
            System.out.println("通讯异常");
            Object errorMsg = map.get("return_msg");
            return new DzResult().error(OrderCode.ORDER_WECAT_ERROR, errorMsg + "");
        }
        if ("FAIL".equals(map.get("result_code"))) {
            System.out.println("支付错误");
            Object errCode = map.get("err_code");
            Object errCodeDes = map.get("err_code_des");
            String errorMsg = errCode + "  :  " + errCodeDes;
            return new DzResult().error(OrderCode.ORDER_WECAT_ERROR, errorMsg + "");
        }
        System.out.println("调统一下单接口返回的结果都OK...............");
        boolean haveMwebUrl = map.containsKey("mweb_url");
        System.out.println("是否有拉起微信APP的路径:" + haveMwebUrl);
        boolean havePrepay_id = map.containsKey("prepay_id");
        System.out.println("是否有,预支付交易会话标识:" + havePrepay_id);
        //新建一个map集合
        Map<String, String> resMap = new HashMap<>(16);
        //appID
        resMap.put("appId", WeChatPayConfig.app_id);
        System.out.println("appId:-->" + resMap.get("appId").toString());
        //时间戳
        resMap.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
        System.out.println("timeStamp:-->" + resMap.get("timeStamp").toString());
        //随机字符串
        resMap.put("nonceStr", WXPayUtil.generateNonceStr());
        System.out.println("nonceStr:-->" + resMap.get("nonceStr").toString());
        //订单详情扩展字段
        resMap.put("package", "prepay_id="+map.get("prepay_id").toString());
        System.out.println("package:-->" + map.get("prepay_id").toString());
        //签名方式
        resMap.put("signType", "MD5");
        String paySign = WXPayUtil.generateSignature(resMap, WeChatPayConfig.partner_key);
        //签名
        resMap.put("paySign", paySign);
        System.out.println("paySign:-->" + resMap.get("paySign").toString());
        //返回给前端
        map.put("WCPayRequest", resMap);
        return new DzResult().success(map);

实现层代码,调统一下单接口代码

/**
     * 微信浏览器内调用JSAPI支付
     *
     * @param outTradeNo
     * @param totalFee
     * @param attachStr
     * @param openID
     * @return
     */
    @Override
    public Map createJSAPI(String outTradeNo, String totalFee, String attachStr, String openID) {
        System.out.println("进入微信内浏览器支付方法");
        System.out.println("传过来的订单号:"+outTradeNo);
        System.out.println("传过来的金额:"+totalFee);
        System.out.println("传过来的自定义参数:"+attachStr);
        System.out.println("传过来的openid:"+openID);
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        //设置失效时间5分钟
        String expireTime = getOrderExpireTime(300 * 1000L);
        //1.创建参数
        HashMap<String, String> param = new HashMap<>(16);
        //公账号
        param.put("appid", WeChatPayConfig.app_id);
        //自定义参数(attach)
        param.put("attach", attachStr);
        //商品描述:商品名字
        param.put("body", "呈衣定制");
        //商户号
        param.put("mch_id", WeChatPayConfig.partner);
        //随机字符串
        param.put("nonce_str", WXPayUtil.generateNonceStr());
        //回调地址
        param.put("notify_url", WeChatPayConfig.notify_url);
        //用户的openID,JSAPI支付必填
        param.put("openid", openID);
        //订单号
        param.put("out_trade_no", outTradeNo);
        //ip,
        param.put("spbill_create_ip", getIpAddr(request));
        //设置失效时间5分钟
        param.put("time_expire", expireTime);
        //总金额(分)
        param.put("total_fee", totalFee);
        //交易类型
        param.put("trade_type", "JSAPI");

        System.out.println("appid"+param.get("appid").toString());
        System.out.println("attach"+param.get("attach").toString());
        System.out.println("body"+param.get("body").toString());
        System.out.println("mch_id"+param.get("mch_id").toString());
        System.out.println("nonce_str"+param.get("nonce_str").toString());
        System.out.println("notify_url"+param.get("notify_url").toString());
        System.out.println("openid"+param.get("openid").toString());
        System.out.println("out_trade_no"+param.get("out_trade_no").toString());
        System.out.println("spbill_create_ip"+param.get("spbill_create_ip").toString());
        System.out.println("time_expire"+param.get("time_expire").toString());
        System.out.println("total_fee"+param.get("total_fee").toString());
        System.out.println("trade_type"+param.get("trade_type").toString());
        System.out.println("partner_key"+WeChatPayConfig.partner_key);
        try {
            //2.生成要发送的xml,方法中传入签名
            String xmlParam = WXPayUtil.generateSignedXml(param, WeChatPayConfig.partner_key);
            System.out.println("调用微信统一下单接口,请求的参数" + xmlParam);
            //请求的url地址
            HttpClient httpclient = new HttpClient(WeChatPayConfig.request_url);
            //是否是https协议
            httpclient.setHttps(true);
            //发送的xml数据
            httpclient.setXmlParam(xmlParam);
            //执行的请求方法
            httpclient.post();
            Map<String, String> returnMap = WXPayUtil.xmlToMap(httpclient.getContent());
            //订单号
            returnMap.put("out_trade_no", outTradeNo);
            //自定义参数,交易信息
            returnMap.put("attach", attachStr);
            System.out.println("调用统一下单接口正常");
            return returnMap;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

六. 前台支付页面里放入微信示例的JS代码就可以拉起微信支付了

在微信浏览器里面打开H5网页中执行JS调起支付。接口输入输出数据格式为JSON。

注意:WeixinJSBridge内置对象在其他浏览器中无效。

getBrandWCPayRequest参数以及返回值定义:

1、网页端接口请求参数列表(参数需要重新进行签名计算,参与签名的参数为:appId、timeStamp、nonceStr、package、signType,参数区分大小写。)

名称 变量名 必填 类型 示例值 描述
公众号id appId 是 String(16) wx8888888888888888 商户注册具有支付权限的公众号成功后即可获得
时间戳 timeStamp 是 String(32) 1414561699 当前的时间,其他详见时间戳规则
随机字符串 nonceStr 是 String(32) 5K8264ILTKCH16CQ2502SI8ZNMTM67VS 随机字符串,不长于32位。推荐随机数生成算法
订单详情扩展字符串 package 是 String(128) prepay_id=123456789 统一下单接口返回的prepay_id参数值,提交格式如:prepay_id=***
签名方式 signType 是 String(32) MD5 签名类型,默认为MD5,支持HMAC-SHA256和MD5。注意此处需与统一下单的签名类型一致
签名 paySign 是 String(64) C380BEC2BFD727A4B6845133519F3AD6 签名,详见签名生成算法
2、返回结果值说明

返回值 描述
get_brand_wcpay_request:ok 支付成功
get_brand_wcpay_request:cancel 支付过程中用户取消
get_brand_wcpay_request:fail 支付失败
调用支付JSAPI缺少参数:total_fee
1、请检查预支付会话标识prepay_id是否已失效

2、请求的appid与下单接口的appid是否一致

注:JS API的返回结果get_brand_wcpay_request:ok仅在用户成功完成支付时返回。由于前端交互复杂,get_brand_wcpay_request:cancel或者get_brand_wcpay_request:fail可以统一处理为用户遇到错误或者主动放弃,不必细化区分。

示例代码如下:

function onBridgeReady(){
   WeixinJSBridge.invoke(
      'getBrandWCPayRequest', {
         "appId":"wx2421b1c4370ec43b",     //公众号名称,由商户传入     
         "timeStamp":"1395712654",         //时间戳,自1970年以来的秒数     
         "nonceStr":"e61463f8efa94090b1f366cccfbbb444", //随机串     
         "package":"prepay_id=u802345jgfjsdfgsdg888",     
         "signType":"MD5",         //微信签名方式:     
         "paySign":"70EA570631E4BB79628FBCA90534C63FF7FADD89" //微信签名 
      },
      function(res){
      if(res.err_msg == "get_brand_wcpay_request:ok" ){
      // 使用以上方式判断前端返回,微信团队郑重提示:
            //res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
      } 
   }); 
}
if (typeof WeixinJSBridge == "undefined"){
   if( document.addEventListener ){
       document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
   }else if (document.attachEvent){
       document.attachEvent('WeixinJSBridgeReady', onBridgeReady); 
       document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
   }
}else{
   onBridgeReady();
}

注意:

签名的时候package字段一定要拼接prepay_id后再进行签名,不然前台拉起微信支付时会报支付验证签名失败
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

微信JSAPI支付,微信浏览器内支付,解决微信H5支付只能在微信外浏览器支付的问题 的相关文章

随机推荐

  • VINS fusion软件架构分析(5)--- 坐标系转换

    对于VINS代码的解读 xff0c 其中一个重要的知识储备就是理解坐标系间的转换 xff0c 这对于后面代码阅读非常重要 xff0c 因此本章重点解释一下 VINS中有3个坐标系 xff1a 世界坐标系 worldIMU坐标系body相机坐
  • 《算法导论》习题5.3-1 ~ 5.3-7

    算法导论 习题 5 3 1 5 3 7 5 3 5 带星号我抄了一下题目 5 3 6 比较有意思我抄了一下题目 其他的题可以自己对照书 原书第三版 5 3 1 直接考虑第2次循环前 第1次循环后第1个位置的元素是原集合1 n中任意一个元素的
  • ROS:坐标系之间的关系 (map \ odom \ base_link)

    ROS 坐标系之间的关系 map odom base link 在使用ROS进行定位与导航操作时 xff0c 会伴随着各种坐标系 xff0c 并且每种坐标系都有明确的含义 xff0c ros中定义了常见的坐标系 xff0c 并且所有的坐标系
  • 上下拉电阻的作用

    这是在论坛上收集到的一些总结 xff1a 一 OC OD门 xff0c 这种门结构如果不做上拉的话 xff0c 是不能实现电平的高底跳变的 xff0c 不能实现跳变 xff0c 便不能表征数据 二 驱动能力 xff0c 我们看很多的CPU或
  • 实测MySQL 查询结果保留两位小数函数的区别汇总

    MySQL查询结果保留两位小数常用的几个函数的区别 xff0c 使用场景 1 随机函数format x d 2 格式化小数函数format x d 例如 xff1a select format 23456 789 2 或 select fo
  • STLINK怎么与STM32单片机连接

    STLink是ST官方开发的单片机仿真工具 xff0c 可以烧写程序 在线仿真 xff0c 使用非常方便 STLink具有两种接口 xff0c 分别为 1 SWD模式 2 SWIM单总线模式 SWD模式主要针对STM32系列的单片机 xff
  • Ubuntu 18.04系统下创建新用户

    以下介绍在Ubuntu 18 04系统下创建新用户 目录 修改用户权限及删除用户的正确方法 在Ubuntu系统上创建新用户使用 sudo useradd 用户名 命令 xff0c 但只能创建用户 xff0c 不能在 home 中创建用户目录
  • 大数据面试题(一)

    一 hdfs写文件的步骤 答案 xff1a 1 client向NameNode申请上传 xxx txt文件 2 NN向client响应可以上传文件 3 Client向NameNode申请DataNode 4 NN向Client返回DN1 D
  • packages.xml和packages.list全解析

    更多干货 xff0c 欢迎关注微信公众号 tmac lover 今天给大家介绍一下Android系统中保存app信息的两个配置文件 xff0c packages xml和packages list 系统中所有安装的app的基本信息在这里都能
  • linux中vim: command not found

    bash vim command not found 1 查看系统是否安装完整vim 2 安装vim 3 我的解决过程 解决问题步骤 xff1a 1 查看系统是否安装完整vim 执行一下命令 xff1a rpm qa grep vim 如果
  • 【FreeRTOS】任务的创建

    启动流程 LiteOS 和 ucos 第一种和第二种都可以使用 xff0c 由用户选择 xff0c RT Thread 和 FreeRTOS 则默认 创建各个任务 xff0c 然后等待启动调度器创建一个起始任务 xff0c 任务都在这个起始
  • 【FreeRTOS】信号量和互斥量

    二值信号量 同步 xff0c 创建时为空 xff0c 任务1获取 xff08 空 xff09 进入阻塞 xff1b 任务2释放信号量 xff0c 于是任务1获取信号量得以进入就绪状态 资源被获取了 xff0c 信号量值就是 0 xff0c
  • 计算机网络笔记:TCP三次握手和四次挥手过程

    TCP是面向连接的协议 xff0c 连接的建立和释放是每一次面向连接的通信中必不可少的过程 TCP连接的管理就是使连接的建立和释放都能正常地进行 三次握手 TCP连接的建立 三次握手建立TCP连接 若主机A中运行了一个客户进程 xff0c
  • echarts与highcharts学习及区别

    1 echarts用法更广泛 xff0c highcharts更适合特定的某些需求 1 1 echarts和highcharts初始引用 xff0c import as echarts from echarts html要有一个容器 xff
  • 啥是驱动?

    Q amp A 什么是驱动 xff1f 驱动本质上是一个软件程序 xff0c 是内核与硬件之间通信的桥梁 xff0c 为应用程序屏蔽了硬件细节 内核可以通过驱动程序去初始化 释放设备 xff0c 内核可以通过驱动程序与设备做双向的数据交互
  • 基于STM32F1系列的OV7725摄像头初步使用(用于摄像头循迹)

    最近做项目需要用到OV7725 xff0c 于是花了些时间研究 由于OV7725对于工作频率的要求较高 xff0c 因此使用带FIFO的摄像头模块 代码参考自正点原子官方 OV7725资源 引脚说明 以下时关于十八个引脚的说明 xff08
  • CAS SSO单点登录实例

    1 因为是本地模拟sso环境 xff0c 而sso的环境测试需要域名 xff0c 所以需要虚拟几个域名出来 xff0c 步骤如下 xff1a 2 进入目录C Windows System32 drivers etc 3 修改hosts文件
  • Ubuntu屏幕录像软件推荐-Kazam

    由于工作的关系 xff0c 需要经常录制一些软件的操作步骤当做教程 xff0c 现在由于使用了Ubuntu单系统平台 xff0c 以前录制的教程均不能正常运行了 xff0c 需要切换到VM xp里面使用 xff0c 造成很大的不变 xff0
  • 图像畸变矫正——透视变换

    图像畸变矫正 透视变换 由于相机制造精度以及组装工艺的偏差引入的畸变 xff0c 或者由于照片拍摄时的角度 旋转 缩放等问题 xff0c 可能会导致原始图像的失真 xff0c 如果要修复这些失真 xff0c 我们可以通过透视变换 xff0c
  • 微信JSAPI支付,微信浏览器内支付,解决微信H5支付只能在微信外浏览器支付的问题

    一 设置支付目录 请确保实际支付时的请求目录与后台配置的目录一致 xff08 现在已经支持配置根目录 xff0c 配置后有一定的生效时间 xff0c 一般5分钟内生效 xff09 xff0c 否则将无法成功唤起微信支付 在微信商户平台 xf