likes
comments
collection
share

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

作者站长头像
站长
· 阅读数 2

什么是第三方API

首先要知道 API 就是应用程序编程接口,就是我们常说的“接口”。在项目内部,后端提供给前端调用的就是接口。而在外部,其他服务商提供给我们的就是第三方接口。 当然,第三方的概念不是绝对的,如果我们自己有个开放平台,向外开放接口,从别人的角度来看我们的就是第三方接口,对自己来讲则是开放 API(Open API)。

API规范

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

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

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

  • 遵循统一的REST的设计风格
  • 使用JSON作为数据交互的格式
  • 所有的API请求必须使用HTTPS
  • 错误码和错误提示
  • 证书/密钥/签名介绍
如何对接并封装微信等第三方服务接口

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

封装第三方服务接口

当我们需要对接第三方 API 时,都应该封装第三方服务接口,这样不仅能提高代码质量和开发效率,还方便后续升级和维护。 我们以对接微信支付为例,解析在开发工作中如何封装第三方服务接口。

集成SDK

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

<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数组类型的数据。其代码片段如下:

{
  "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 的封装和业务对接演示,可以看到在业务中整个代码流程清晰顺畅,调用层次简单,基本不会涉及很底层的代码编码。且在业务实现中也无需关心对签名、验签、证书等等的处理,让业务真正回到业务。