如何对接并封装微信等第三方服务接口

什么是第三方API

首先要知道 API 就是应用程序编程接口,就是我们常说的"接口"。在项目内部,后端提供给前端调用的就是接口。而在外部,其他服务商提供给我们的就是第三方接口。

当然,第三方的概念不是绝对的,如果我们自己有个开放平台,向外开放接口,从别人的角度来看我们的就是第三方接口,对自己来讲则是开放 API(Open API)。

API规范

无论是我们自己开发的接口,还是第三方接口,都需要遵循一定的设计规范,例如:

  • RESTful API,接口遵循RESTful风格。
  • 接口安全,包括身份认证,防止重放,签名规则等。

我们以 微信商户平台接口规则 文档为参考,可以看到 API 的规则描述,如:

  • 遵循统一的REST的设计风格
  • 使用JSON作为数据交互的格式
  • 所有的API请求必须使用HTTPS
  • 错误码和错误提示
  • 证书/密钥/签名介绍

在开发中,我们通常主要关注 API 的基本规则;而对于数据加解密,请求签名与验证签名这类规则,在官方提供的 SDK 中都会集成,比如wechatpay-apache-httpclient其中的WechatPayHttpClientBuilder会帮助我们完成身份认证与请求签名。

封装第三方服务接口

当我们需要对接第三方 API 时,都应该封装第三方服务接口,这样不仅能提高代码质量和开发效率,还方便后续升级和维护。

我们以对接微信支付为例,解析在开发工作中如何封装第三方服务接口。

集成SDK

为了减轻开发工作量,集成 SDK 是最省时省力的方法。这里我们引入 微信支付服务端SDK

xml 复制代码
<dependency>
  <groupId>com.github.wechatpay-apiv3</groupId>
  <artifactId>wechatpay-apache-httpclient</artifactId>
  <version>0.4.8</version>
</dependency>

内容拆分

第三方接口文档整个的内容会很多,但总体都是围绕介绍接口的请求与响应。比如微信支付的 JSAPI下单 ,它主要有接口说明、请求参数、应答参数,以及错误码。因此我们在项目代码中可以划分出:

  • api,存放接口URL常量
  • request,存放请求参数的实体类
  • response,存放响应参数的实体类

同时,微信支付 API 还有回调通知,如 支付通知 ,这里也单独划分出:

  • notify,存放通知参数的实体类

此外,在开发中我们还要再考虑其他相关的类,比如工具类,配置类等:

  • util,存放工具类,比如用于 HTTP 请求,加解密之类的
  • config,配置类,用于加载请求必要的身份信息、证书、密钥等属性
  • client,客户端,用于发起请求的类,其中定义了各个接口的请求与响应

我们将上面的内容分门别类,划分到不同的包中,在代码中的目录结构中如下:

config

我们先从配置类出发,因为这是开发工作前的一切。对于微信支付来讲,我们要用到的APIv3密钥商户API证书商户API私钥等支付相关的都需要提前在商户平台中申请与配置。

以下是微信支付配置类的一个示例:

api

接下来是存放接口URL的常量类。URL中有些是完整的请求地址,也有的是需要拼接参数的字符串模版,比如 微信支付订单号查询订单/v3/pay/transactions/id/{transaction_id}。我们可以依照官方给的照搬,也可以改成代码适用的,将{transaction_id}改成%s

以下是微信支付 APIv3 的一个示例:

request、response、notify

我们不推荐使用Mapputget请求参数和响应的数据,因为根据过往开发经历,那样会使得代码冗余冗长,也会对代码阅读造成困扰。因此分别定义了 request、response、notify 这些存放参数相关的实体类。

在查阅微信支付 API 文档时,会发现无论是接口的请求参数还是应答参数,其数据体都是有结构的,比如在 JSAPI下单 请求参数中,除了appid等外层的数据,还嵌套了detail数据,而detail中还继续嵌套了goods_detail数组类型的数据。其代码片段如下:

json 复制代码
{
  "appid" : "wxd678efh567hg6787",
  "mchid" : "1230000109",
  "detail" : {
    "cost_price" : 608800,
    "goods_detail" : [
      {
        "merchant_goods_id" : "1246464644"
      }
    ]
  }
}

在代码中,我们依照官方文档给的数据结构,依样编码实体类,有嵌套的数据的就将其作为嵌套类。需要注意的是,无论内部嵌套多少层,每个类都需要实现Serializable用于序列化;同时嵌套类修饰为静态的,则是为了便于引用。

以下是JSAPI下单请求参数的实体类示例:

client

client 就是客户端,是业务代码中向第三方服务 API 发起请求的类,它向下是HttpClient,向上则是service层;client 就如工具类一样,其中定义了不同的静态方法,每个方法都对应了一个第三方 API。

以下是微信支付客户端的示例:

在上面的WechatPayClient#prepay方法中,入参是 request,返回则是接口对应的 response。但是需要注意的是,并不是所有的第三方 API 都会返回有结构数据,比如微信小程序中 获取小程序码 返回参数说明如下:

如果调用成功,会直接返回图片二进制内容,如果请求失败,会返回 JSON 格式的数据。

这样的话,方法的返回参数不能直接用实体类了,而应该用ResponseResponseBody接收,之后再返回上层service处理。例如微信小程序中 获取不限制的小程序码 的方法示例如下:

util

util 用于存放工具类,比如用于 HTTP 请求,加解密,签名验证,证书管理等等的。通常在第三方的 SDK 中都有提供这类工具类,但是为了适配业务,有时候也需要在这些工具类的基础上再封装。

以下是一个用于微信支付 HTTP 请求的工具类示例:

业务对接

当我们完成第三方 API 的封装后,就可以对接业务了。

控制层

这里以下单业务对接微信支付为例,在支付环节中,当用户点击提交订单,此时服务端生成订单后向微信发起预支付(即 JSAPI下单/APP下单/Native下单......),等待预支付成功后返回前端并由前端调起支付面板,用户付款才最终完成支付。

以下是一个预支付接口示例:

服务层

在控制层中,预支付方法只做基本的流程控制,其核心业务(PayService#prepay)交由服务层处理。核心业务中包括 request 参数实体类的组装,客户端请求的调用(WechatPayClient#prepay)以及响应数据的处理。

业务代码如下:

总结

经过对第三方服务 API 的封装和业务对接演示,可以看到在业务中整个代码流程清晰顺畅,调用层次简单,基本不会涉及很底层的代码编码。且在业务实现中也无需关心对签名、验签、证书等等的处理,让业务真正回到业务。

相关推荐
苏三说技术1 小时前
Claude Code从失控到起飞,只用了这些技巧
后端
长栎2 小时前
写 for 循环写了十年,你却从没用过迭代器模式最狠的那一面
后端
LiaCode2 小时前
Redis 在生产项目的使用
前端·后端
用户559822481222 小时前
Docker Compose Down 导致容器数据误删——ext4 日志恢复全记录
后端
LiaCode2 小时前
一天学完 redis 的爽翻版核心知识总结
前端·后端
大刚测试开发实战2 小时前
如何内网穿透访问本地私有化部署的TestHub
前端·后端·github
xiaodaoluanzha3 小时前
迄今為止,最簡單的編程語言 Nolang
前端·后端
Csvn3 小时前
Docker 容器管理入门 — 从镜像到容器编排
后端
用户762352425913 小时前
ShardingJDBC
后端
行者全栈架构师3 小时前
IDEA 中 Maven 项目的 15 个红色报错快速解决方法
java·后端