Hello, I’m Shendi

最近开发 H5 项目,需要接入微信支付,这里记录一下

文章目录

  • 场景
  • 接入前准备
  • 选择 SDK
  • 初始化
  • 不同的地方
  • 下单
    • JSAPI 下单需要 openid 的获取方式
    • JSAPI下单
  • 前端调起
  • 支付回调
  • 查询订单
  • 关闭订单

场景

项目是 H5 项目,这里踩坑了,以为接入 H5 支付就可以了,后面发现 H5 支付只能在微信外调用,所以后面连忙加入 JSAPI 支付

H5支付
H5支付是指商户在微信客户端外的移动端网页展示商品或服务,用户在前述页面确认使用微信支付时,商户发起本服务呼起微信客户端进行支付。

说明:要求商户已有H5商城网站,并且已经过ICP备案,即可申请接入。

申请开通需要3-5天

JSAPI支付

JSAPI支付是指商户通过调用微信支付提供的JSAPI接口,商户的支付场景是在微信内置浏览器打开调起支付完成收款。

好像默认就开通,开通好像是秒开

接入前准备

微信支付官方的文档已经比较详细了,可以先从指引文档,基础支付入手

https://pay.weixin.qq.com/wiki/doc/apiv3_partner/index.shtml

需要用到 appid,具体参考文档,有个公众号就可以了

然后就是关于商户的一些信息及证书(参考文档)

对于 JSAPI 接入,需要用到用户的 openid,所以需要在公众号内配置

公众号 -> 设置与开发 -> 公众号设置 -> 功能设置 -> 网页授权域名

JSAPI是在 js 内调起支付,所以这个地方域名填写前端域名就可以了(基本上配置域名配置前端域名就可以了),配置的时候要将txt文件放到前端服务器的根目录才可以确认

需要注意的是,目前这个域名配置只能配置两个,网上的解决办法是搭个反向代理服务器

选择 SDK

在微信官方文档的指引文档中的开发指引,选择对应的 SDK

我使用的 Java 所以直接用第一个就可以了
https://github.com/wechatpay-apiv3/wechatpay-apache-httpclient

Maven方式引入

<dependency><groupId>com.github.wechatpay-apiv3</groupId><artifactId>wechatpay-apache-httpclient</artifactId><version>0.4.7</version>
</dependency>

初始化

首先需要加载商户私钥,平台证书,初始化 httpClient …
关于证书,大概有三个文件

  • apiclient_cert.p12
  • apiclient_cert.pem
  • apiclient_key.pem

首先要安装证书,windows下直接双击 apiclient_cert.p12 即可,剩下的自己看需求操作,Linux自行百度

其中 apiclient_key.pem 是商户私钥

获取私钥的代码封装

/*** 获取私钥。** @param filename 私钥文件路径  (required)* @return 私钥对象*/
public static PrivateKey getPrivateKey(String filename) throws IOException {String content = new String(Files.readAllBytes(Paths.get(filename)), "utf-8");try {String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "").replace("-----END PRIVATE KEY-----", "").replaceAll("\\s+", "");KeyFactory kf = KeyFactory.getInstance("RSA");return kf.generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));} catch (NoSuchAlgorithmException e) {throw new RuntimeException("当前Java环境不支持RSA", e);} catch (InvalidKeySpecException e) {throw new RuntimeException("无效的密钥格式");}
}

初始化代码如下

/** 平台证书管理器 */
private static CertificatesManager certificatesManager;
/** 商户私钥 */
private static PrivateKey privateKey;
/** 如果你是使用Apache HttpClient的商户开发者,可以使用它构造HttpClient。得到的HttpClient在执行请求时将自动携带身份认证信息,并检查应答的微信支付签名。 */
private static CloseableHttpClient httpClient = null;//--- 此处参数根据自己的内容赋值
/** 商户id */
private String mchId;
/** 商户序列号 */
private String mchSerialNo;
/** api_v3_key */
private String apiV3Key;public static void init() {// 加载商户私钥(privateKey:私钥字符串)privateKey = getPrivateKey("apiclient_key.pem文件地址"));// 获取证书管理器实例certificatesManager = CertificatesManager.getInstance();// 向证书管理器增加需要自动更新平台证书的商户信息certificatesManager.putMerchant(mchId, new WechatPay2Credentials(mchId,new PrivateKeySigner(mchSerialNo, privateKey)),apiV3Key.getBytes(StandardCharsets.UTF_8));// 初始化httpClienthttpClient = WechatPayHttpClientBuilder.create().withMerchant(mchId, mchSerialNo, privateKey).withValidator(new WechatPay2Validator(certificatesManager.getVerifier(mchId))).build();
}

在项目启动的时候执行 init() 初始化就可以了

不同的地方

对于后端来说,H5支付和JSAPI支付不同的地方差不多只有下单部分
下单部分有些参数不一样,以及返回不一样,还有 url 不一样,以及前端调起支付的方式不一样

查询订单,退款,支付通知这些一模一样,可以通用

下单

H5支付或者JSAPI支付,第一步是下单,下单在指引文档中都有代码示例,这里不过多阐述。文档内使用的是字符串追加形式拼接的参数,我们可以改为JSONObject

H5 下单比较简单,服务端下单后,响应一串 url,将这串 url 给前端,让前端跳转到此 url 即可完成调用微信支付,付款

JSAPI 则需要先获取到用户 openid,然后带上 openid 下单

公司需求是两者都要有,所以对于前端,判断浏览器是否为微信内置浏览器代码如下

function isWeixin(){return navigator.userAgent.indexOf("MicroMessenger")>0;
}if (isWeixin()) {// jsapi...
} else {// h5...
}

是微信则调用 JSAPI下单
不是则h5下单

在下单完成,一般将订单存入数据库,状态为待付款即可

JSAPI 下单需要 openid 的获取方式

这里主要记录下 JSAPI 的 openid 获取方式
文档 https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html

公司有公众号,于是appid用的公众号的,还需要公众号的 secret

文档里面有以下几步

我们只需要获取 openid,所以只需要第一,第二步即可,第一步参考文档让用户跳转组装好的url就可以了,其中如果提示 redirect_uri 错误之类的则是公众号内未配置此域名

用户跳转后会跳到 redirect_uri,并携带参数 code

踩坑,回调后,code参数是在最外层框架上,即使在iframe内跳转,所以需要使用 parent.location 等去获取 code

获取到code第一步就完成了

第二步是前端拿着code去请求后端,后端要有个接口,内容大致如下

// https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
StringBuilder url = new StringBuilder();
url.append("https://api.weixin.qq.com/sns/oauth2/access_token")
.append("?appid=").append("公众号appid")
.append("&secret=").append("公众号secret")
.append("&code=").append("第一步获取到的code")
.append("&grant_type=").append("authorization_code");HttpsURLConnection huc = null;
try {huc = (HttpsURLConnection) new URL(url.toString()).openConnection();huc.setRequestMethod("GET");huc.setDoInput(true);huc.setDoOutput(true);// readAllBytes 是读取所有字节, Java9及以上才有String data = new String(huc.getInputStream().readAllBytes());JSONObject result = (JSONObject) JSONObject.parse(data);if (isError(result)) {// 有错误} else {// 拿到了 openid, 响应给用户即可String openid = result.get("openid");}
} catch (IOException e) {e.printStackTrace();
} finally {if (huc != null) huc.disconnect();
}

其中判断结果是否有误的函数如下(可通用)

/*** 判断返回的数据是否为错误数据.* @param json 返回的数据* @return true为错误数据,false为正确数据*/
public static boolean isError(JSONObject json) {return json.getString("errcode") != null && !json.getString("errcode").equals("0");
}

前端拿到 openid 后调用下单接口即可

JSAPI下单

下单不复杂,但是前端调起需要的参数麻烦,这里就格外说一下
下单和h5差不多,响应一串字符串(h5是url),但是和h5不一样,不需要将这一串字符串响应给前端,而是需要自己组装参数发给前端

可以看JSAPI开发指引的这一部分

timeStamp 是当前时间戳(毫秒) / 1000 即可(秒)
nonceStr 是需要自己生成,随机字符串
… 具体参考文档,签名生成方式如下

// 签名
StringBuilder paySignBuild = new StringBuilder();
paySignBuild.append(appid).append("\n").append(timeStamp).append("\n").append(nonceStr).append("\n").append(packageStr).append("\n");// 签名方式
Signature sign = Signature.getInstance("SHA256withRSA");
// 商户私钥
sign.initSign(privateKey);
sign.update(paySignBuild.toString().getBytes());String paySign = Base64.getEncoder().encodeToString(sign.sign());

将这些信息都发给前端即可

前端调起

H5的话后端下单完,响应的是一个url,将url给前端,前端跳转即可

跳转完,不管支付成功与否,都会退回到当前页面,在有些设备内会导致刷新,所以需要自己保存状态

JSAPI 则是直接调起,支付完不会刷新页面,调起代码在开发指引文档上有,参数改成后端返回的参数即可

踩坑,WeixinJSBridge内置对象在其他浏览器中无效,在 iframe 内必须在最顶层框架才有此对象,例如 parent.WeixinJSBridge

参数中 timeStamp 必须是字符串类型,例如 timeStamp + “”,否则在 IOS 中会出错

支付完成后显示是否支付完成提示框,当用户点击我已完成支付就去查询订单状态即可

支付回调

下单有一个必须携带的参数 notify_url,当支付完成后,微信会请求此参数对应的接口,要确保这个接口不需要任何验证即可访问(必须https,且请求类型为POST)

我的需求只需要知道商户订单号即可

我直接用的 Servlet,代码如下,其中 PayUtil.getLog().log() 为日志,供参考

public class PayCallBackServlet extends HttpServlet {private static final long serialVersionUID = 1L;@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {byte[] data = req.getInputStream().readAllBytes();if (data == null) {PayUtil.getLog().log("支付回调,获取数据为空, ip=%s", IPUtil.get(req));return;}String body = new String(data);System.out.println(body);try {// 构建request,传入必要参数NotificationRequest request = new NotificationRequest.Builder().withSerialNumber(PayUtil.getPlatformC()).withNonce(req.getHeader("Wechatpay-Nonce")).withTimestamp(req.getHeader("Wechatpay-Timestamp")).withSignature(req.getHeader("Wechatpay-Signature")).withBody(body).build();NotificationHandler handler = new NotificationHandler(certificatesManager.getVerifier(mchId), apiV3Key.getBytes(StandardCharsets.UTF_8));// 验签和解析请求体Notification notification = handler.parse(request);// 获取商户订单号,根据订单号查询结果PayUtil.getLog().log("接收到支付回调内容, ip=%s, data=%s", IPUtil.get(req), notification.toString());JSONObject dDataObj = JSONObject.parseObject(notification.getDecryptData());String tradeId = dDataObj.getString("out_trade_no");// tradeId 为商户id, 进行操作 ...// 这里最好是再通过商户id去查询订单状态,状态和数据库内状态不一致在改变/完成,否则有可能造成资金损失PayUtil.getLog().log("支付回调完成, trade=%s, ip=%s, info=%s", tradeId, IPUtil.get(req), result);} catch (Exception e) {e.printStackTrace();PayUtil.getLog().log("处理回调通知出错: error=%s, ip=%s", e.getMessage(), IPUtil.get(req));}}}

查询订单

分为通过微信订单号查询,和通过商户号查询
参考文档中的开发指引即可

查询订单,判断数据库内订单状态是否一致,不一致则再处理

关闭订单

同查询订单
参考文档中的开发指引即可

H5网站接入微信支付(H5支付+JSAPI支付)相关推荐

  1. 2021年PC电脑网站接入微信登陆支付精讲--1小时自已就可动手接入功能,--所有流程一目了然

    2021年了,你还要疲于拼命吗,2001年初,遇到BUG就是躲,放下,去吃最好吃的,吃好喝好,睡一觉,再来解决, 现在是喜欢上BUG了,出现BUG,就发自内心的想搞清楚,是什么源因导致的,呵呵呵 PC ...

  2. PC网站接入微信登陆流程四:后端处理登陆后的code,和获取微信登陆用户的信息

    1.文档在这里 ==>> 授权后接口调用(UnionID) 2.前端登陆成功后,需要提交code给后端,后端接受到请求后,进行处理,下面的例子均为Python版本 第一步:通过code获取 ...

  3. uni-app - 最详细 H5 网页接入微信支付功能,提供从详细的示例代码与注释(移动端网页实现微信支付能力,微信公众号前端支付 JSAPI / JS-SDK 详细示例源码)官方最新超级详细教程

    前言 关于 uni-app 项目中接入微信支付的文章鱼龙混杂,各种 JSAPI / JS-SDK 乱代码.过时.没注释.不讲流程原理,非常难用. 本文实现了 uni-app H5 移动端网页项目,实现 ...

  4. 微信公众号 - H5 网页接入微信支付(JSAPI)

    前言 假设您已经申请成为微信商户(认证)且各项配置弄好了,并且开通 JSAPI 支付等,只差代码(前端)编写. 如果你之前不了解,强烈建议 先看一遍如下标注的文档: [官方文档]网页客户端(H5),需 ...

  5. H5网站接入支付宝的支付接口

    写本文章的目的是为了记录工作中遇到的问题,方便以后遇到可以迅速解决问题 H5手机网站接入支付宝的支付接口,推荐使用支付宝提供的SDK来快速开发 我使用的是SDK开发 引用命名空间 using Aop. ...

  6. phpcms实现PC网站接入微信Native支付

    微信支付-PC网站接入支付 微信支付支持完成域名ICP备案的网站接入支付功能.PC网站接入支付后,可以通过JSAPI支付或Native支付,自行开发生成二维码,用户使用微信"扫一扫" ...

  7. 微信开发 - 第三方网站接入微信登录、微信支付时,本地 redirect_uri 参数错误导致无法调试的解决方案(微信开放平台)完美解决每次都需要部署到线上测试,在本地使用本地 ip 就能轻松调试

    问题描述 网上的教程都非常乱且无效,本文将站在新手的角度,超级详细的讲解. 本文提供 在微信开放平台,接入微信登录和微信支付时,本文无法调试 redirect_uri 回调错误 的解决方案, 仅需几个 ...

  8. 微信首页登录html页面,H5页面接入微信授权登录和分享

    前期准备 接入微信授权 分静默授权和非静默授权两种 静默授权: scope=snsapi_base,没有弹窗,只能获取用户的openId. 非静默授权: scope=snsapi_userinfo,有 ...

  9. uni-app - 最详细 H5 网页接入微信登录功能,提供公众号配置与详细注释示例代码(移动端网页实现点击登录按钮后 调用微信公众号授权登录功能 详细讲解接入流程与详细示例代码)官方最新超级详细教程

    前言 关于 uni-app 项目中接入微信授权登录的文章鱼龙混杂,各种乱代码.过时.没注释.不讲流程原理,非常难用. 本文实现了 uni-app H5 移动端网页项目,实现微信授权登录功能,详细讲解接 ...

  10. 微信支付开发(5)--JSAPI支付开发详解

    点此查看 微信公众号/微信网页/微信支付/企业微信/小程序开发合集及源代码下载 本文目录 1. 场景 2. 普通商户支付 2.1 构建项目 2.2 编写配置类 2.3 网页授权获取openid 2.4 ...

最新文章

  1. FFT与多项式、生成函数题目泛做
  2. selenium3+python-多窗口、句柄(handle)
  3. DataGridView怎样实现添加、删除、上移、下移一行
  4. Redux之compose
  5. 各品牌类型电脑BOIS中USB模式启动热键
  6. python 识别图形验证码_Python验证码识别
  7. pytorch torch.nn.MSELoss
  8. 《C程序设计语言》笔记 (三) 控制流
  9. “互联网+”从业务本质重构业务形态
  10. 凯辉基金与法投行完成对资管软件公司NeoXam的投资 加速企业国际化发展布局
  11. 排查DHCP服务器故障
  12. Python 数据科学手册
  13. 《线性代数》(同济版)——教科书中的耻辱柱
  14. 2016.2.14-2016.2.21 中大信(北京)工程造价咨询有限公司实习有感
  15. 使用密码查看器查看软件的密码
  16. 温控PLC三菱风机程序设计多路多路风机,温度控制,时间控制
  17. undefined reference to `timersub‘ 错误处理
  18. 软件著作权转让的流程是怎么样的
  19. java的框架_java 三大框架——spring
  20. RetinaNet——《Focal Loss for Dense Object Detection》论文翻译

热门文章

  1. 让我康康,是谁进了 Hack for wuhan 初赛?
  2. 飞翔(风吹)的flash文字
  3. AutoCAD 2019 mac中文
  4. 鸡兔同笼问题c语言编程,鸡兔同笼问题C语言程序编写
  5. Linux【环境部署 02】yum源镜像下载+挂载镜像+本地yum源配置+局域网yum源服务搭建+局域网yum源使用(一篇学会离线yum源配置)
  6. 雕虫小技 - 签名图片生成器
  7. 在Linux下安装软件
  8. 大数据为你解读2017年全国出差地图
  9. 视频相似度检测算法软件,视频相似度检测算法图
  10. WinMTR - 路由跟踪及PING测试软件