微信小程序开发实战11_1 微信支付下单

news2024/9/27 7:20:55

微信支付流程图

微信支付存在多个业务流程,包括微信支付流程、退款流程等。本章节主要介绍微信的支付下单流程,图12-1是微信支付流程的交互图:
在这里插入图片描述
重点环节说明

  • 步骤1:小程序端用户向商户服务器发起支付请求,重点是提供用户信息、商品信息、支付金额等参数。
  • 步骤3:商户服务器调用支付统一下单接口生成微信支付订单,调用成功后返回预支付交易会话标识(prepay_id),该参数将用于小程序前端的接口调用。
  • 步骤6:获取prepay_id后,需要再次签名,然后把签名参数以及prepay_id等参数返回给小程序。
  • 步骤9:小程序调用接口:wx.requestPayment调起微信支付,发起支付请求。
  • 步骤15:用户支付成功后,商户服务器可接收到微信支付支付结果通知,商户服务器收到通知后更新订单的支付状态。
  • 步骤20:商户在没有接收到微信支付结果通知的情况下需要主动调用查询订单API查询支付结果。

12.1提交支付订单

商户系统调用该接口生成预支付交易单。提交支付订单的请求URL为:
https://api.mch.weixin.qq.com/v3/pay/partner/transactions/jsapi
提交支付订单的接口的请求参数如下:

参数名变量描述
服务商应用IDsp_appid必填)服务商申请的公众号appid。
服务商户号sp_mchid(必填)服务商户号,由微信支付生成并下发
子商户应用IDsub_appid(必填)子商户申请的公众号appid。若sub_openid有传的情况下,sub_appid必填,且sub_appid需与sub_openid对应
子商户号sub_mchid(必填)子商户的商户号,由微信支付生成并下发。
商品描述description(必填)商品描述
商户订单号out_trade_no(必填)商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一。
结束时间time_expire订单失效时间。
附加数据attach附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用
通知地址notify_url(必填)通知URL必须为直接可访问的URL,不允许携带查询串。
优惠标记goods_tag订单优惠标记
+结算信息settle_info结算信息
-是否分账profit_sharing是否指定分账,枚举值true:是false:否
+订单金额amount(必填)订单金额信息
-总金额total(必填)订单总金额,单位为分。
-货币类型currencyCNY:人民币,境内商户号仅支持人民币。
+支付者payer支付者信息
-用户标识sp_openid用户在服务商appid下的唯一标识。
-用户子标识sub_openid用户在子商户appid下的唯一标识。若传sub_openid,那sub_appid必填

调用成功后返回:预支付交易会话标识(prepay_id),该参数用于小程序前端的接口调用中,该值的有效期为2小时。以下是实现提交支付订单的代码逻辑,首先给出的是统一下接口使用的数据结构:

//订单数据
type WxAppOrderData struct {
   //子商户用ID(服务商)
   Sub_appid          string `json:"sub_appid,omitempty"`
   //子商户的商户号(服务商)
   Sub_mchid          string `json:"sub_mchid,omitempty"`
   //商品描述
   Description        string `json:"description"`
   //商户系统内部订单号
   Out_trade_no       string `json:"out_trade_no"`
   //交易结束时间
   Time_expire        string `json:"time_expire,omitempty"`
   //附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用
   Attach                string `json:"attach,omitempty"`
   //通知URL必须为直接可访问的URL,不允许携带查询串
   Notify_url           string `json:"notify_url"`
   //订单优惠标记
   Goods_tag          string `json:"goods_tag,omitempty"`
   //订单金额信息
   Amount OrderCreateAmount      `json:"amount"`
   //支付者信息
   Payer OrderPayer            `json:"payer"`
   //统一下单结算信息
   Settle_info OrderCreateSettle  `json:"settle_info"`
}

//统一下单请求参数
type WxAppOrderCreateReq struct {
   //应用ID(普通商户)
   Appid             string `json:"appid,omitempty"`
   //直连商户号(普通商户)
   Mchid                 string `json:"mchid,omitempty"`
   //服务商用ID(服务商)
   Sp_appid              string `json:"sp_appid,omitempty"`
   //服务商户号(服务商)
   Sp_mchid           string `json:"sp_mchid,omitempty"`
   //订单数据
   WxAppOrderData
}

//统一下单返回参数
type WxAppOrderCreateRet struct {
   //详细错误码
   Return_code       string     `json:"code"`
   //错误描述
   Return_msg        string     `json:"message"`
   //预支付交易会话标识。用于后续接口调用中使用,该值有效期为2小时
   Prepay_id         string     `json:"prepay_id"`
}

微信支付为直连商户模式以及服务商模式提供了不同的调用接口(具有不同的接口地址以及请求参数)。本文中直连商户模式以及服务商模式共用一套数据结构,并通过json的omitempty标签来适应两种模式的区别。接下来给出服务商模式下接口调用的实现逻辑:

//支付统一下单
//data:支付订单信息
func (ent *MchWxapp) createOrderX(data WxAppOrderData) (WxAppPayParam, error)  {
   var preq WxAppOrderCreateReq
   preq.Sp_appid = ent.Appid
   preq.Sp_mchid = ent.Mchid
   preq.WxAppOrderData = data
   data_body, _ := json.Marshal(preq)

   var param_ent WxAppPayParam
   var pret WxAppOrderCreateRet
   const url = "https://api.mch.weixin.qq.com/v3/pay/partner/transactions/jsapi"
   result, err := WxPayPostV3((*MchParam)(ent), url, data_body)
   if err != nil {
      return param_ent, err
   }
   err = json.Unmarshal([]byte(result), &pret)
   if err != nil {
      fmt.Println(err)
      return param_ent, err
   }
   if pret.Prepay_id == "" {
      return param_ent, errors.New(pret.Return_msg)
   }

   //小程序客户端支付参数
   param_ent.Appid = preq.Sub_appid
   param_ent.TimeStamp = fmt.Sprintf("%d", time.Now().Unix())
   param_ent.NonceStr, _= GenerateNonce()
   param_ent.Prepay_id = pret.Prepay_id
   param_ent.Package = "prepay_id=" + pret.Prepay_id
   param_ent.SignType = "RSA"
   param_ent.PaySign, _ = param_ent.GenPaySignV3(ent.MchPrivateKey)
   return param_ent, nil
}

通过JSAPI下单成功获取预支付交易会话标识(prepay_id)后,需要通过小程序调用支付API(wx.requestPayment)来拉起微信客户端进行支付。wx.requestPayment需要将请求参数进行签名,签名计算的逻辑如下:
1)构造签名串
签名串一共有四行,每一行为一个参数。行尾以\n结束,包括最后一行。参与签名字段及格式为:
小程序appId\n时间戳\n随机字符串\n订单详情扩展字符串\n
2)计算签名值
使用商户私钥对签名串进行SHA256 with RSA签名,并对签名结果进行Base64编码得到签名值。
接下来给出小程序参数签名计算的实现代码,首先给出返回给小程序所需的支付数据的数据结构:

type WxAppPayParam struct{
   Appid string
   TimeStamp string
   NonceStr string
   Prepay_id string
   Package string
   SignType string
   PaySign string
}

接下来使用商户私钥对签名串进行SHA256 with RSA签名,并对签名结果进行Base64编码来计算签名值:

func (ent *WxAppPayParam)GenPaySignV3(mch_pem_key *rsa.PrivateKey) (string, error) {
   SignatureMessageFormat := "%s\n%s\n%s\n%s\n"
   message := fmt.Sprintf(SignatureMessageFormat, ent.Appid, ent.TimeStamp, ent.NonceStr, ent.Package)
   signatureResult, err := SignSHA256WithRSA(mch_pem_key, message)
   if err != nil {
      return "", err
   }
   return signatureResult, nil
}

直连商户的下单接口与服务商下单接口基本一致,除了接口地址不同外,下单时不需要提供子商户号(sub_mchid), 也不需要提供子商户子商户的应用ID(sub_appid)。直连商户下单接口的请求URL为:
https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi
直连商户下单接口的请求参数如下:

参数名变量描述
应用IDappidbody 由微信生成的应用ID,全局唯一。请求基础下单接口时请注意APPID的应用属性,例如公众号场景下,需使用应用属性为公众号的APPID
直连商户号mchidbody 直连商户的商户号,由微信支付生成并下发。
商品描述descriptionbody 商品描述
商户订单号out_trade_nobody 商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一
交易结束时间time_expire body订单失效时间,time_expire只能第一次下单传值,不允许二次修改,二次修改系统将报错。如用户支付失败后,需再次支付,需更换原订单号重新下单。
附加数据attachbody 附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用
通知地址notify_urlbody异步接收微信支付结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数。 公网域名必须为https,如果是走专线接入,使用专线NAT IP或者私有回调域名可使用http
订单优惠标记goods_tagbody 订单优惠标记
订单金额amountbody 订单金额信息
支付者payerbody 支付者信息
优惠功能detailbody 优惠功能
场景信息scene_infobody 支付场景描述
结算信息settle_infobody 结算信息

以下是直连商户下单接口访问的代码实现:

func (ent *MchWxapp) createOrder(data WxAppOrderData) (WxAppPayParam, error)  {
   var preq WxAppOrderCreateReq
   preq.Appid = ent.Appid
   preq.Mchid = ent.Mchid
   preq.WxAppOrderData = data
   data_body, _ := json.Marshal(preq)

   var param_ent WxAppPayParam
   var pret WxAppOrderCreateRet
   const url = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi"
   result, err := WxPayPostV3((*MchParam)(ent), url, data_body)
   if err != nil {
      return param_ent, err
   }

   err = json.Unmarshal([]byte(result), &pret)
   if err != nil {
      return param_ent, err
   }

   if pret.Prepay_id == "" {
      return param_ent, errors.New(pret.Return_msg)
   }

   //小程序客户端支付参数
   param_ent.Appid = preq.Appid
   param_ent.TimeStamp = fmt.Sprintf("%d", time.Now().Unix())
   param_ent.NonceStr, _= GenerateNonce()
   param_ent.Prepay_id = pret.Prepay_id
   param_ent.Package = "prepay_id=" + pret.Prepay_id
   param_ent.SignType = "RSA"
   param_ent.PaySign, _ = param_ent.GenPaySignV3(ent.MchPrivateKey)
   return param_ent, nil
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/129707.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Appium基础 — webview操作(重点)

我们之前说过的所有操作,都是对原生页面的操作。 在手机APP中,除了原生页面,还是有webview页面(也就是H5页面),下面我们就说说对webview页面的操作。 1、先了解什么是Hybrid(混合)…

【Web安全】Ysoserial 简单利用

Ysoserial 简单利用1. Java 反序列化特征2. Ysoserial 流量特征3. Ysoserial 攻击流程3.1 找到序列化接口3.2 漏洞利用3.2.1 常用命令3.2.2 使用案例4. Ysoserial 攻击原理问题参考1. Java 反序列化特征 在日志中,特征通常表现为 请求格式 Json、xml、soap、二进制…

拓扑排序的java代码实现过程详解

拓扑排序 在现实生活中,我们经常会同一时间接到很多任务去完成,但是这些任务的完成是有先后次序的。以我们学习java学科为例,我们需要学习很多知识,但是这些知识在学习的过程中是需要按照先后次序来完成的。从java基础&#xff0c…

中国电信携手鼎桥创新中心开展终端优选测评工作

近期,中国电信物联网开放实验室与鼎桥创新中心本着“优势互补、合作共赢、共同发展”的原则,携手联合开展了中国电信CTWing物联网市场终端优选测试,完成了多款行业智能终端的测评,为物联网市场上架产品的质量保驾护航,…

Node.js--》Express和路由模块的讲解使用

目录 Express Express的安装与使用 托管静态资源 nodemon Express路由 模块化路由 Express Express是基于Node.js平台,快速、开放、极简的Web开发框架。Express的作用和Node.js内置的http模块类似,是专门用来创建Web服务器的。Express的本质&…

cubeIDE开发, stm32独立看门狗IWDT的CubeMX配置及HAL库底层实现分析

一、STM32 的IWDT简介 2.1 看门狗原理 看门狗本质上就是一种计数器,和我们现实生活中一炷香现象、沙漏现象等是同理的,计数器一般有两种做法,一种是递增,超过固定阀值报警;一种是递减,通常值降到0时报警。后…

数据结构训练营5

开启蓝桥杯备战计划,每日练习算法一题!!坚持下去,想必下一年的蓝桥杯将会有你!!笔者是在力扣上面进行的刷题!!由于是第一次刷题!找到的题目也不咋样!所以&…

Databend in 2022

上一次写总结还是在回顾 Datafuse Labs 成立一周年,转眼来到 22 年末,Databend 也快要开始第三个年头的征程了。 今天就让我们一起回顾一下 Databend 在 2022 年的成果。 开源 Databend 是一款强大的云数仓,专为弹性和高效设计&#xff0c…

Spring Authorization Server 1.0 提供 Oauth 2.1 和 OpenID Connect 1.0 实现

1. 概述 在引入Java 社区两年半之后,VMWare发布了Spring Authorization Server 1.0。Spring 授权服务器项目构建在Spring Security之上,支持创建OpenID Connect 1.0身份提供者和OAuth 2.1授权服务器。该项目取代了不再维护的 Spring Security OAuth项目…

RHCEansible虚拟机初始化配置,ansible配置和安装

1.保证三台主机能互相通信,需要设置同一种网络模式(nat) 2.配置静态ip地址(命令行,图形界面都可以) server---192.168.171.100 node1---192.168.171.222 node2---192.168.171.10 3.更改主机名 永久更…

C++代码编程学习(1):简易通讯录的创建

2022年圣诞节到来啦,很高兴这次我们又能一起度过~ CSDN诚邀各位技术er分享关于圣诞节的各种技术创意,展现你与众不同的精彩!参与本次投稿即可获得【话题达人】勋章【圣诞快乐】定制勋章(1年1次,错过要等下一年喔&#…

消费市场的“跨年”:2023,数字新消费将引领市场何去何从?

配图来自Canva可画 2022,变局如同一个过滤器,每一个身处其中的消费者和消费品牌都在经受考验。我国人口红利在消退,竞争在加剧,需求在变化。光大证券研究所的数据显示,2022年来我国居民收入增速小幅改善,但…

Spring之Bean创建过程

1. 前言 Spring提供了xml、注解、JavaConfig多种方式来配置bean,不论何种方式,Spring最终都会将bean封装成BeanDefinition对象,Spring创建bean的依据也是通过BeanDefinition来完成的。 当我们调用getBean()方法获取bean实例时,不…

jmeter使用教程之登录接口(工作日记)

首先我们打开jmeter 快捷按钮:winr 会弹出快捷运行弹框,我们输入cmd 后点击回车 会弹出一个控制窗口,我们输入jmeter,然后回车 首次进入jmeter,页面显示空白页且默认英文 我们可以切换语言 【Options - Choose Lan…

AI前沿 | 利用训练好的模型库进行一键抠图(实例演示)

来源:投稿 作者:Struggling cyanobacteria 编辑:学姐 深度学习平台飞浆paddle的环境搭建 ① 效率更高的 gpu 版本的安装 通过 python -m pip install paddlepaddle-gpu -i https://mirror.baidu.com/pypi/simple来进行安装。 paddle.utils…

Dockerfile了解

目录 1.自定义centos,具备vim及ifconfig作用 2.自定义tomcat8 1.自定义centos,具备vim及ifconfig作用 cd /javaxl/software mkdir mydocker vi mycentosDockerfile 向 mycentosDockerfile 编辑内容 FROM centos:7 MAINTAINER zwc "zwcqq.com"…

解决Windows下使用cmd执行Python文件报错 ModuleNotFoundError: No module named ‘XXXX‘

一、问题产生 我在IDEA中可以正常执行的Python文件,想把它配置成每天固定时间执行的定时任务。我写了一个脚本在每天9点时执行Python文件,但是我在cmd中测试执行时遇到以下报错: Traceback (most recent call last):File "D:\dev\code…

AD5328手册翻译不完全(仅供参考)

最近要用到DAC生成数据波形,但是都是英文不好阅读,于是花费点时间翻译了大致数据内容并记录 一、特性 AD5308:16导联TSSOP中的8个缓冲8位DAC A版本:1 LSB INL,B版本:0.75 LSB INR AD5318:16导联TSSOP中的8个缓冲10…

互联网时代,VR全景营销的意义是什么?

互联网时代,很多事项我们都可以在手机上解决,随着互联网的不断发展,年轻人每天花在手机上的时间也在日益增加,这就将压力给到了线下实体店铺,年轻人不喜欢逛街,线下店铺的获客成本就会越来越高。同时也是由…

无人机测深三种方法-激光雷达,测深仪和探地雷达

最近搜素了论文和相关网页,博主总结了一下无人机测深总共有三种办法: (1)激光雷达; (2)测深仪; (3)探地雷达(GPR)。 1、激光雷达 …