- 
                Notifications
    You must be signed in to change notification settings 
- Fork 276
SDK 配置详解
为了在集成到你的系统后能正常运行,SDK 需要以下两个部分的配置:
- 商户配置。例如,商户 API 私钥、商户 API 证书序列号、APIv3Key 等。
- HTTP 配置。例如,超时时间、代理地址等。
商户配置主要是商户的身份信息,用于构造请求的签名和验证应答的签名。
为了适配开发者不同的密钥基础设施,SDK 对商户配置做了抽象。
- 面向底层 HttpClient,将配置抽象成身份认证实体 Credential和应答验证实体Validator。
- 面向开发者,SDK 使用 Config接受商户配置,并为 HTTP 客户端提供所需的Credential和Validator。
如果你在你的服务内部署商户 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 在构造时会首次下载证书。如果首次下载失败,构造将失败,并抛出异常。
它还包含一个后台线程定时更新微信支付平台证书(目前设计为60分钟),实现了当前证书过期时的新老证书平滑切换。如果在更新时下载失败,则不抛出异常,并继续使用之前的证书。
代码片段-配置商户信息 演示了如何构造 RSAAutoCertificateConfig 并用它初始化一个 Service。
限制:每个商户号只能创建一个 RSAAutoCertificateConfig。同一个商户号构造多个实例,会抛出 IllegalStateException 异常。我们建议你将配置类作为全局变量。如果你的程序是多线程,应使用多线程安全的单例模式。
RSAAutoCertificateConfig.Builder 增加的配置方法见下表。
| 方法 | 说明 | 
|---|---|
| apiV3Key(String) | APIv3 密钥 | 
| httpClientBuilder() | 见代理配置 | 
如果你不想使用 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 客户端也采用了生成器模式,网络配置通过生成器设置。
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()。
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();很多开发者的网络环境限制了访问外网需经过代理。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();