Skip to content

SDK 配置详解

Xiaoyu PENG edited this page Aug 16, 2023 · 5 revisions

为了在集成到你的系统后能正常运行,SDK 需要以下两个部分的配置:

  • 商户配置。例如,商户 API 私钥、商户 API 证书序列号、APIv3Key 等。
  • HTTP 配置。例如,超时时间、代理地址等。

商户配置

商户配置主要是商户的身份信息,用于构造请求的签名和验证应答的签名。

为了适配开发者不同的密钥基础设施,SDK 对商户配置做了抽象。

  • 面向底层 HttpClient,将配置抽象成身份认证实体 Credential 和应答验证实体 Validator
  • 面向开发者,SDK 使用 Config 接受商户配置,并为 HTTP 客户端提供所需的 CredentialValidator

如果你在你的服务内部署商户 API 私钥,可使用 SDK 提供的 Config 实现类。

因为配置项众多导致构造函数有多个参数,Config 实现都采用了生成器(Builder)模式。Builder 提供了以下配置方法:

方法 说明
merchantId(String) 商户号
merchantSerialNumber(String) 商户 API 证书的证书序列号
privateKey(String) 私钥字符串
privateKey(PrivateKey) 私钥对象
privateKeyFromPath(String) 本地私钥文件的路径字符串

不过,以上商户配置还不够。为了验证 API 应答签名,SDK 还需要微信支付平台证书。根据不同的平台证书提供方式,SDK 提供了两种 Config 实现类:

  • RSAConfig。由 SDK 使用方,即商户开发者,提供本地微信支付平台证书,并在证书过期前人工更新证书。
  • RSAAutoCertificateConfig。由 SDK 自动下载,并定时更新微信支付平台证书。

使用 RSAAutoCertificateConfig

我们推荐使用 RSAAutoCertificateConfig,因为它无需开发者人工维护微信支付平台证书,使用更简单更可靠。

RSAAutoCertificateConfig 在构造时会首次下载证书。如果首次下载失败,构造将失败,并抛出异常。

它还包含一个后台线程定时更新微信支付平台证书(目前更新间隔设计为60分钟),实现了当前证书过期时的新老证书平滑切换。如果在更新时下载失败,则不抛出异常,并继续使用之前的证书。

代码片段-配置商户信息 演示了如何构造 RSAAutoCertificateConfig 并用它初始化一个 Service。

RSAAutoCertificateConfig.Builder 增加的配置方法见下表。

方法 说明
apiV3Key(String) APIv3 密钥
httpClientBuilder() 代理配置

使用 RSAConfig

如果你不想使用 SDK 提供的定时更新平台证书,你可以使用 RSAConfig 加载本地证书。

Config config =
    new RSAConfig.Builder()
        .merchantId(merchantId)
        .privateKeyFromPath(privateKeyPath)
        .merchantSerialNumber(merchantSerialNumber)
        .wechatPayCertificatesFromPath(wechatPayCertificatePath)
        .build();

// 以JsapiService为例,使用 config 初始化 service
JsapiService service = new JsapiService.Builder().config(config).build();

除了一般的配置方法外,它新增的配置方法见下表。

方法 说明
wechatPayCertificatesFromPath(String...) 本地微信支付平台证书的路径,支持多个
wechatPayCertificates(String...) 微信支付平台证书字符串,支持多个

网络配置

跟商户配置一样,HTTP 客户端也采用了生成器模式,网络配置通过生成器设置。

使用 DefaultHttpClientBuilder

SDK 使用 OkHttp 作为底层的 HTTP 客户端。如果开发者不熟悉 OkHttp,推荐使用 SDK 封装的 DefaultHttpClientBuilder 来构造 HTTP 客户端。

目前支持的网络配置方法见下表。

方法 说明 默认值 更多信息
readTimeoutMs() 设置新连接的默认读超时 10*1000(10秒) OkHttpClient/Builder/readTimeout
writeTimeoutMs() 设置新连接的默认写超时 10*1000(10秒) OkHttpClient/Builder/writeTimeout
connectTimeoutMs() 设置新连接的默认连接超时 10*1000(10秒) OkHttpClient/Builder/connectTimeout
proxy() 设置客户端创建的连接时使用的 HTTP 代理 OkHttpClient/Builder/proxy

下面的示例演示了如何使用 DefaultHttpClientBuilder 初始化某个具体的业务 Service。

HttpClient httpClient =
    new DefaultHttpClientBuilder()
        .config(config)
        .connectTimeoutMs(500)
        .build();

// 以JsapiService为例,使用 httpclient 初始化 service
JsapiService service = new JsapiService.Builder().httpclient(httpClient).build();

PS:由于微信支付 API 请求需要签名和验签,HTTP 客户端的运行也依赖了商户配置。所以,除了网络配置外,生成器还提供了设置商户配置的方法 DefaultHttpClientBuilder.config()

使用自定义 OkHttpClient.Builder

SDK 支持使用方自定义 OkHttpClient。这样开发者可以直接从底层更丰富地配置 HTTP 客户端的行为,例如:超时、重试、HTTP 拦截器

下面的代码演示了如何使用 OkHttpClient.Builder 配置超时。更多配置,请直接查阅 OkHttpClient.Builder 的文档

Config config =
    new RSAAutoCertificateConfig.Builder()
        .merchantId(merchantId)
        .privateKeyFromPath(privateKeyPath)
        .merchantSerialNumber(merchantSerialNumber)
        .apiV3Key(apiV3key)
        .build();

OkHttpClient client = new OkHttpClient.Builder()
        .connectTimeout(10, TimeUnit.SECONDS)
        .writeTimeout(10, TimeUnit.SECONDS)
        .readTimeout(30, TimeUnit.SECONDS)
        .build();

HttpClient httpClient =
    new DefaultHttpClientBuilder()
        .config(config)
        .okHttpClient(okHttpClient)
        .build();

// 以JsapiService为例,使用 httpclient 初始化 service
JsapiService service = new JsapiService.Builder().httpclient(httpClient).build();

代理配置(v0.2.6起开始支持)

很多开发者的网络环境限制了访问外网需经过代理。SDK 在 DefaultHttpClientBuilder 中提供了 proxy() 方法。

// 使用 proxy 设置代理
HttpClient httpClient =
    new DefaultHttpClientBuilder()
        .config(config)
        .proxy(new Proxy(Type.SOCKS, new InetSocketAddress("localhost", 8099))
        .build();

// 使用 httpclient 初始化 service
JsapiService service = new JsapiService.Builder().httpclient(httpClient).build();

但是,这种方式不适用于自动更新证书的 RSAAutoCertificateConfig。因为 RSAAutoCertificateConfig 自身就需要一个可用的 HTTP 客户端,跟 DefaultHttpClient 产生了循环依赖。

  graph LR;
      RSAAutoCertificateConfig-->HttpClient;
      HttpClient-->DefaultHttpClient;
      DefaultHttpClient-->RSAAutoCertificateConfig;

正确的方式是使用 RSAAutoCertificateConfig.Builder.httpClientBuilder() 方法,通过 HttpClientBuilder 将网络配置传递给证书下载器。

示例代码如下:

// 设置下载自动更新证书时网络配置
DefaultHttpClientBuilder clientBuilder = 
    new DefaultHttpClientBuilder()
        .proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("localhost", 8099));

// 设置商户配置,并使用 httpClientBuilder 设置 HttpClient 所需的网络配置
Config config =
    new RSAAutoCertificateConfig.Builder()
        .merchantId(merchantId)
        .privateKeyFromPath(privateKeyPath)
        .merchantSerialNumber(merchantSerialNumber)
        .apiV3Key(apiV3key)
        .httpClientBuilder(clientBuilder)
        .build();

这样,RSAAutoCertificateConfig 会使用 clientBuilder 提供的网络配置,包括代理配置。

接下来,如果在业务请求时,你希望沿用下载证书时的商户配置和网络配置,只需将新得到的 Config 设置到 clientBuilder 中,得到 Service 可用的 HTTP 客户端。

// case1: 继续使用网络配置 
clientBuilder.config(config);
JsapiService service = new JsapiService.Builder()
        .httpclient(clientBuilder.build())
        .build();

如果在业务请求时,你希望使用一组新的网络配置,那么你可以将 Config 设置到新的 HttpClientBuilder 中,重新构造 HTTP 客户端。这样,下载证书会使用之前的网络配置,而在业务请求时使用新的网络配置。

// case2: 如果希望另外设置 API 请求的网络配置,可以这样构造 Service
HttpClient httpClient = new DefaultHttpClientBuilder.Builder()
        .config(config)
        .proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("localhost", 8099)))
        .connectTimeoutMs(10 * 1000)
        .build()
JsapiService service = new JsapiService.Builder()
        .httpClient(httpClient)
        .build();