Giter Club home page Giter Club logo

wechatpay-java's Introduction

JavaDoc Maven Central Security Rating Maintainability Rating Coverage

微信支付 APIv3 Java SDK

微信支付 APIv3 官方 Java 语言客户端开发库。

开发库由 coreservice 组成:

  • core 为基础库,包含自动签名和验签的 HTTP 客户端、回调处理、加解密库。
  • service 为业务服务,包含业务接口使用示例

帮助微信支付改进

为了向广大开发者提供更好的使用体验,微信支付诚挚邀请您反馈使用微信支付 Java SDK 中的感受。您的反馈将对改进 SDK 大有帮助,点击参与问卷调查

前置条件

  • Java 1.8+。
  • 成为微信支付商户
  • 商户 API 证书:指由商户申请的,包含证书序列号、商户的商户号、公司名称、公钥信息的证书。
  • 商户 API 私钥:商户申请商户API证书时,会生成商户私钥,并保存在本地证书文件夹的文件 apiclient_key.pem 中。
  • APIv3 密钥:为了保证安全性,微信支付在回调通知和平台证书下载接口中,对关键信息进行了 AES-256-GCM 加密。APIv3 密钥是加密时使用的对称密钥。

快速开始

安装

最新版本已经在 Maven Central 发布。

Gradle

在你的 build.gradle 文件中加入如下的依赖

implementation 'com.github.wechatpay-apiv3:wechatpay-java:0.2.12'

Maven

加入以下依赖

<dependency>
  <groupId>com.github.wechatpay-apiv3</groupId>
  <artifactId>wechatpay-java</artifactId>
  <version>0.2.12</version>
</dependency>

调用业务请求接口

以 Native 支付下单为例,先补充商户号等必要参数以构建 config,再构建 service 即可调用 prepay() 发送请求。

package com.wechat.pay.java.service;

import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.service.payments.nativepay.NativePayService;
import com.wechat.pay.java.service.payments.nativepay.model.Amount;
import com.wechat.pay.java.service.payments.nativepay.model.PrepayRequest;
import com.wechat.pay.java.service.payments.nativepay.model.PrepayResponse;

/** Native 支付下单为例 */
public class QuickStart {

    /** 商户号 */
    public static String merchantId = "190000****";
    /** 商户API私钥路径 */
    public static String privateKeyPath = "/Users/yourname/your/path/apiclient_key.pem";
    /** 商户证书序列号 */
    public static String merchantSerialNumber = "5157F09EFDC096DE15EBE81A47057A72********";
    /** 商户APIV3密钥 */
    public static String apiV3Key = "...";

    public static void main(String[] args) {
        // 使用自动更新平台证书的RSA配置
        // 一个商户号只能初始化一个配置,否则会因为重复的下载任务报错
        Config config =
                new RSAAutoCertificateConfig.Builder()
                        .merchantId(merchantId)
                        .privateKeyFromPath(privateKeyPath)
                        .merchantSerialNumber(merchantSerialNumber)
                        .apiV3Key(apiV3Key)
                        .build();
        // 构建service
        NativePayService service = new NativePayService.Builder().config(config).build();
        // request.setXxx(val)设置所需参数,具体参数可见Request定义
        PrepayRequest request = new PrepayRequest();
        Amount amount = new Amount();
        amount.setTotal(100);
        request.setAmount(amount);
        request.setAppid("wxa9d9651ae******");
        request.setMchid("190000****");
        request.setDescription("测试商品标题");
        request.setNotifyUrl("https://notify_url");
        request.setOutTradeNo("out_trade_no_001");
        // 调用下单方法,得到应答
        PrepayResponse response = service.prepay(request);
        // 使用微信扫描 code_url 对应的二维码,即可体验Native支付
        System.out.println(response.getCodeUrl());
    }
}

从示例可见,使用 SDK 不需要计算请求签名和验证应答签名。详细代码可从 QuickStart 获得。

示例

查询支付订单

QueryOrderByIdRequest queryRequest = new QueryOrderByIdRequest();
queryRequest.setMchid("190000****");
queryRequest.setTransactionId("4200001569202208304701234567");

try {
  Transaction result = service.queryOrderById(queryRequest);
  System.out.println(result.getTradeState());
} catch (ServiceException e) {
  // API返回失败, 例如ORDER_NOT_EXISTS
  System.out.printf("code=[%s], message=[%s]\n", e.getErrorCode(), e.getErrorMessage());
  System.out.printf("reponse body=[%s]\n", e.getResponseBody());
}

关闭订单

CloseOrderRequest closeRequest = new CloseOrderRequest();
closeRequest.setMchid("190000****");
closeRequest.setOutTradeNo("out_trade_no_001");
// 方法没有返回值,意味着成功时API返回204 No Content
service.closeOrder(closeRequest);

下单并生成调起支付的参数

JSAPI 支付和 APP 支付推荐使用服务拓展类 JsapiServiceExtensionAppServiceExtension,两者包含了下单并返回调起支付参数方法。

JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build();

// 跟之前下单示例一样,填充预下单参数
PrepayRequest request = new PrepayRequest();

// response包含了调起支付所需的所有参数,可直接用于前端调起支付
PrepayWithRequestPaymentResponse response = service.prepayWithRequestPayment(request);

上传图片

import com.wechat.pay.java.service.file.FileUploadService;
import com.wechat.pay.java.service.file.model.FileUploadResponse;

FileUploadService fileService = new FileUploadService.Builder().config(config).build();
FileUploadResponse fileUploadResponse = fileUploadService.uploadImage(uploadUrl, meta, imagePath);

更多示例

为了方便开发者快速上手,微信支付给每个服务生成了示例代码 XxxServiceExample.java,可以在 example 中查看。 例如:

错误处理

SDK 使用的是 unchecked exception,会抛出四种自定义异常。每种异常发生的场景及推荐的处理方式如下:

  • HttpException:调用微信支付服务,当发生 HTTP 请求异常时抛出该异常。
    • 构建请求参数失败、发送请求失败、I/O错误:推荐上报监控和打印日志,并获取异常中的 HTTP 请求信息以定位问题。
  • ValidationException :当验证微信支付签名失败时抛出该异常。
    • 验证微信支付返回签名失败:上报监控和日志打印。
    • 验证微信支付回调通知签名失败:确认输入参数与 HTTP 请求信息是否一致,若一致,说明该回调通知参数被篡改导致验签失败。
  • ServiceException:调用微信支付服务,发送 HTTP 请求成功,HTTP 状态码小于200或大于等于300。
    • 状态码为5xx:主动重试。
    • 状态码为其他:获取错误中的 errorCodeerrorMessage,上报监控和日志打印。
  • MalformedMessageException:服务返回成功,返回内容异常。
    • HTTP 返回 Content-Type 不为 application/json:不支持其他类型的返回体,下载账单 应使用 download() 方法。
    • 解析 HTTP 返回体失败:上报监控和日志打印。
    • 回调通知参数不正确:确认传入参数是否与 HTTP 请求信息一致,传入参数是否存在编码或者 HTML 转码问题。
    • 解析回调请求体为 JSON 字符串失败:上报监控和日志打印。
    • 解密回调通知内容失败:确认传入的 apiV3 密钥是否正确。

自动更新微信支付平台证书

为确保 API 请求过程中的安全性,客户端需要使用微信支付平台证书来验证服务器响应的真实性和完整性。 从 v0.2.3 版本开始,我们引入了一个名为 RSAAutoCertificateConfig 的配置类,用于自动更新平台证书。

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

RSAAutoCertificateConfig 会利用 AutoCertificateService 自动下载微信支付平台证书。 AutoCertificateService 将启动一个后台线程,定期(目前为每60分钟)更新证书,以实现证书过期时的平滑切换。

在每次构建 RSAAutoCertificateConfig 时,SDK 首先会使用传入的商户参数下载一次微信支付平台证书。 如果下载成功,SDK 会将商户参数注册或更新至 AutoCertificateService。若下载失败,将会抛出异常。

为了提高性能,建议将配置类作为全局变量。 复用 RSAAutoCertificateConfig 可以减少不必要的证书下载,避免资源浪费。 只有在配置发生变更时,才需要重新构造 RSAAutoCertificateConfig

如果您有多个商户号,可以为每个商户构建相应的 RSAAutoCertificateConfig

Note 从 v0.2.10 开始,我们不再限制每个商户号只能创建一个 RSAAutoCertificateConfig

使用本地的微信支付平台证书

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

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

回调通知

首先,你需要在你的服务器上创建一个公开的 HTTP 端点,接受来自微信支付的回调通知。 当接收到回调通知,使用 notification 中的 NotificationParser 解析回调通知。

具体步骤如下:

  1. 使用回调通知请求的数据,构建 RequestParam
    • HTTP 请求体 body。切记使用原始报文,不要用 JSON 对象序列化后的字符串,避免验签的 body 和原文不一致。
    • HTTP 头 Wechatpay-Signature。应答的微信支付签名。
    • HTTP 头 Wechatpay-Serial。微信支付平台证书的序列号,验签必须使用序列号对应的微信支付平台证书。
    • HTTP 头 Wechatpay-Nonce。签名中的随机数。
    • HTTP 头 Wechatpay-Timestamp。签名中的时间戳。
    • HTTP 头 Wechatpay-Signature-Type。签名类型。
  2. 初始化 RSAAutoCertificateConfig。微信支付平台证书由 SDK 的自动更新平台能力提供,也可以使用本地证书。
  3. 初始化 NotificationParser
  4. 调用 NotificationParser.parse() 验签、解密并将 JSON 转换成具体的通知回调对象。如果验签失败,SDK 会抛出 ValidationException
  5. 接下来可以执行你的业务逻辑了。如果执行成功,你应返回 200 OK 的状态码。如果执行失败,你应返回 4xx 或者 5xx的状态码,例如数据库操作失败建议返回 500 Internal Server Error
// 构造 RequestParam
RequestParam requestParam = new RequestParam.Builder()
        .serialNumber(wechatPaySerial)
        .nonce(wechatpayNonce)
        .signature(wechatSignature)
        .timestamp(wechatTimestamp)
        .body(requestBody)
        .build();

// 如果已经初始化了 RSAAutoCertificateConfig,可直接使用
// 没有的话,则构造一个
NotificationConfig config = new RSAAutoCertificateConfig.Builder()
        .merchantId(merchantId)
        .privateKeyFromPath(privateKeyPath)
        .merchantSerialNumber(merchantSerialNumber)
        .apiV3Key(apiV3Key)
        .build();

// 初始化 NotificationParser
NotificationParser parser = new NotificationParser(config);

try {
  // 以支付通知回调为例,验签、解密并转换成 Transaction
  Transaction transaction = parser.parse(requestParam, Transaction.class);
} catch (ValidationException e) {
  // 签名验证失败,返回 401 UNAUTHORIZED 状态码
  logger.error("sign verification failed", e);
  return ResponseEntity.status(HttpStatus.UNAUTHORIZED);
}

// 如果处理失败,应返回 4xx/5xx 的状态码,例如 500 INTERNAL_SERVER_ERROR
if (/* process error */) {
  return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR);
}

// 处理成功,返回 200 OK 状态码
return ResponseEntity.status(HttpStatus.OK);

常用的通知回调调对象类型有:

  • 支付 Transaction
  • 退款 RefundNotification
  • 若 SDK 暂不支持的类型,请使用 Map.class,嵌套的 Json 对象将被转换成 LinkedTreeMap

你既可以为每个通知回调使用不同的 HTTP 端点,也可以使用一个端点根据 event_type 处理不同的通知回调。 我们建议,不同的通知回调使用不同的端点,直接调用 SDK 处理通知回调,避免商户自己解析报文。因为 SDK 会先验证通知回调的有效性,可有效防止"坏人"的报文攻击。

发送 HTTP 请求

如果 SDK 未支持你需要的接口,你可以使用 OkHttpClientAdapter 的实现类发送 HTTP 请求,它会自动生成签名和验证签名。

发送请求步骤如下:

  1. 初始化 OkHttpClientAdapter,建议使用 DefaultHttpClientBuilder 构建。
  2. 构建请求 HttpRequest
  3. 调用 httpClient.execute 或者 httpClient.get 等方法来发送 HTTP 请求。httpClient.execute 支持发送 GET、PUT、POST、PATCH、DELETE 请求,也可以调用指定的 HTTP 方法发送请求。

OkHttpClientAdapterTest 中演示了如何构造和发送 HTTP 请求。如果现有的 OkHttpClientAdapter 实现类不满足你的需求,可以继承 AbstractHttpClient 拓展实现。

下载账单

因为下载的账单文件可能会很大,为了平衡系统性能和签名验签的实现成本,账单下载API 被分成了两个步骤:

  1. /v3/bill/tradebill 申请账单下载链接,并获取账单摘要。
  2. /v3/billdownload/file 账单文件下载,请求需签名但应答不签名。

SDK 提供了 HttpClient.download() 方法。它返回账单的输入流。开发者使用完输入流后,应自主关闭流。

InputStream inputStream = httpClient.download(downloadUrl);

// 非压缩的账单可使用 core.util.IOUtil 从流读入内存字符串,大账单请慎用
String respBody = IOUtil.toString(inputStream);
inputStream.close();

Warning

开发者在下载文件之后,应使用第一步获取的账单摘要校验文件的完整性。

敏感信息加解密

为了保证通信过程中敏感信息字段(如用户的住址、银行卡号、手机号码等)的机密性,

  • 微信支付要求加密上送的敏感信息
  • 微信支付会加密下行的敏感信息

详见 接口规则 - 敏感信息加解密

自动加解密

如果 SDK 已支持的接口,例如商家转账,SDK 将根据契约自动对敏感信息做加解密:

  • 发起请求时,开发者设置原文。SDK 自动加密敏感信息,并设置 Wechatpay-Serial 请求头
  • 收到应答时,解密器自动解密敏感信息,开发者得到原文

手动加解密

如果 SDK 尚未支持某个接口,你可以使用 cipher 中的 RSAPrivacyEncryptorRSAPrivacyDecryptor ,手动对敏感信息加解密。

当你使用自动获取的微信支付平台证书时,可以通过以下方法获取加密器 PrivacyEncryptor,以及对应的证书序列号。

PrivacyEncryptor encryptor = config.createEncryptor();
String wechatPayCertificateSerialNumber = encryptor.getWechatpaySerial();
String ciphertext = encryptor.encryptToString(plaintext);

当你使用本地的公钥或私钥,可以通过以下方法直接构建加密器 PrivacyEncryptor 和解密器 PrivacyDecryptor

// 微信支付平台证书中的公钥
PublicKey wechatPayPublicKey = null;
String plaintext = "";
PrivacyEncryptor encryptor = new RSAPrivacyEncryptor(wechatPayPublicKey);
String ciphertext = encryptor.encryptToString(plaintext);
// 商户私钥
PrivateKey merchantPrivateKey = null;
String ciphertext = "";
PrivacyDecryptor decryptor = new RSAPrivacyDecryptor(merchantPrivateKey);
String plaintext = decryptor.decryptToString(ciphertext);

RSAPrivacyEncryptorTestRSAPrivacyDecryptorTest 中演示了如何使用以上函数做敏感信息加解密。

日志

SDK 使用了 SLF4j 作为日志框架的接口。这样,你可以使用你熟悉的日志框架,例如 LogbackLog4j2 或者 SLF4j-simple。 SDK 的日志会跟你的日志记录在一起。

为了启用日志,你应在你的构建脚本中添加日志框架的依赖。如果不配置日志框架,默认是使用 SLF4j 提供的 空(NOP)日志实现,它不会记录任何日志。

网络配置

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
disableRetryOnConnectionFailure() 遇到网络问题时不重试下一个 IP 默认重试 OkHttpClient/Builder/retryOnConnectionFailure
enableRetryMultiDomain() 遇到网络问题时重试备域名 默认不重试 推荐开启,详细说明见下

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

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

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

更多网络配置的说明,请看 wiki - 网络配置

双域名容灾

为提升商户系统访问 API 的稳定性,SDK 实现了双域名容灾。如果主要域名 api.mch.weixin.qq.com 因网络问题无法访问,我们的 SDK 可自动切换到备用域名 api2.wechatpay.cn 重试当前请求。 这个机制可以最大限度减少因微信支付 API 接入点故障或主域名问题(如 DNS 劫持)对商户系统的影响。

默认情况下,双域名容灾机制处于关闭状态,以避免重试降低商户系统的吞吐量。因为 OkHttp 默认会尝试主域名的多个IP地址(目前为2个),增加备用域名重试很可能会提高异常情况下的处理时间。

我们推荐开发者使用 disableRetryOnConnectionFailureenableRetryMultiDomain 的组合,启用双域名容灾并关闭 OkHttp 默认重试,这样不会增加重试次数。

假设 api.mch.weixin.qq.com 解析得到 [ip1a, ip1b],api2.wechatpay.cn 解析得到 [ip2a, ip2b],不同的重试策略组合对应的尝试顺序为:

  • 默认:[ip1a, ip1b]
  • disableRetryOnConnectionFailure:[ip1a]
  • enableRetryMultiDomain:[ipa1, ip1b, ip2a, ip2b]
  • (推荐)disableRetryOnConnectionFailure + enableRetryMultiDomain: [ip1a, ip2a]

以下是采用推荐重试策略的示例代码:

// 开启双域名重试,并关闭 OkHttp 默认的连接失败后重试
HttpClient httpClient =
    new DefaultHttpClientBuilder()
        .config(config)
        .disableRetryOnConnectionFailure()
        .enableRetryMultiDomain()
        .build();

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

开发者应该仔细评估自己的商户系统容量,根据自身情况选择合适的超时时间和重试策略,并做好监控和告警。

使用国密

我们提供基于 腾讯 Kona 国密套件 的国密扩展。文档请参考 shangmi/README.md

常见问题

为什么收到应答中的证书序列号和发起请求的证书序列号不一致?

请求和应答使用 数字签名 ,保证数据传递的真实、完整和不可否认。为了验签方能识别数字签名使用的密钥(特别是密钥和证书更换期间),微信支付 APIv3 要求签名和相应的证书序列号一起传输。

  • 商户请求使用商户API私钥签名。商户应上送商户证书序列号。
  • 微信支付应答使用微信支付平台私钥签名。微信支付应答返回微信支付平台证书序列号。

综上所述,请求和应答的证书序列号是不一致的。

证书和回调解密需要的 AesGcm 解密在哪里?

请参考 AeadAesCipherAeadAesCipherTest

由于 SDK 已经提供了微信支付平台证书下载服务 CertificateService 以及回调通知解析器 NotificationParser ,这两者会完成所有的解析与解密工作。因此除非你想要自定义实现,否则你应该不需要用到 AeadXxxCipher 中提供的方法。

为什么我使用 NotificationHandler 验证回调通知失败,抛出 ValidationException

如果你使用的是 SDK 自动更新的微信支付平台证书,验证失败原因是:参与验证的参数不正确。从开发者反馈来看,大部分失败案例没有使用回调原始 body,而是用 body 反序列化得到的对象再做 JSON 序列化得到的 body。很遗憾,这样的 body 几乎一定跟原始报文不一致,所以签名验证不通过。具体案例可参考 #112

如果你使用的是本地的微信支付平台证书,请检查微信支付平台证书是否正确,不要把商户证书和微信支付平台证书搞混了。

如何计算前端签名?

有一部分 API 需要计算前端签名,例如调起支付、调起支付分小程序等。

  • 调起支付签名,SDK 提供了下单并生成调起支付参数的方法,请参考 示例

  • 其他场景计算签名,请参考 JsapiServiceExtension 使用 Signer 计算签名的例子。

为什么快速开始的示例程序执行后,程序不会退出?

在 v0.2.10 中,我们将定时更新证书的线程设置为后台线程,程序可以正常退出了。

如何参与开发

微信支付欢迎来自社区的开发者贡献你们的想法和代码。请你在提交 PR 之前,先提一个对应的 issue 说明以下内容:

  • 背景(如,遇到的问题)和目的。
  • 着重说明你的想法。
  • 通过代码或者其他方式,简要的说明是如何实现的,或者它会是如何使用。
  • 是否影响现有的接口。

联系微信支付

如果你发现了 BUG,或者需要的功能还未支持,或者有任何疑问、建议,欢迎通过 issue 反馈。

也欢迎访问微信支付的 开发者社区

wechatpay-java's People

Contributors

a39676 avatar a8520238 avatar alanfc666 avatar bytechen avatar cadmusjiang avatar chaoyuxie avatar chengpanfei avatar colindhlin avatar hanxiating avatar lianup avatar sexybear avatar thinkerchi avatar twinklelx avatar v-jinyewang avatar xy-peng avatar yuxiangque avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

wechatpay-java's Issues

我拉了最新的版本缺少类 RSAAutoCertificateConfig

错误描述

我拉了最新的版本缺少类 RSAAutoCertificateConfig

重现bug的步骤

image
Uploading image.png…

预期行为

直接maven下载就行

导致错误的代码片段

No response

操作系统

macos

Java 版本

1.8

wechatpay-java 版本

0.2.2

其他信息

No response

请问,微信支付的v3-javasdk部分是实习生在维护么?

错误描述

基本没有体现什么面向对象的**,所有的request,rep连接口都没有
其次有些用法非常无语,比如notify的时候,要传requestbody进sdk解密,但是回调类型又写在解密前的字符串里面,很多吧,感觉怎么用怎么别扭,我一下午。
要不然发外包把这个sdk整一下吧,不然咱这小公司什么时候上v3啊。

重现bug的步骤

1

预期行为

1

导致错误的代码片段

@PostMapping("/notify/{tenantCode}")
    public String wxPayNotify(@PathVariable String tenantCode, @RequestBody String body, HttpServletRequest request){
        BaseContextHandler.setTenant(tenantCode);
        Notification notification = JSONUtil.toBean(body,Notification.class);

        RequestParam requestParam = new RequestParam
                .Builder()
                .serialNumber(request.getHeader("Wechatpay-Serial"))
                .nonce(request.getHeader("Wechatpay-Nonce"))
                .signature(request.getHeader("Wechatpay-Signatur"))
                .signType(request.getHeader("Wechatpay-Signature-Type"))
                .body(body)
                .build();

        // 根据type做出多种结果处理
        return payService.parseOrderNotifyResultV3(requestParam,notification.getResource().getOriginalType());
    }


### 操作系统

macos

### Java 版本

1.8

### wechatpay-java 版本

21

### 其他信息

1

NotificationParser类第92行,异常提示值不匹配问题

错误描述

image

NotificationParser类第92行,异常提示值不匹配问题

重现bug的步骤

控制台排查问题不友好

预期行为

友好查看异常信息

导致错误的代码片段

![image](https://user-images.githubusercontent.com/33826351/202381290-a683ed10-01e5-4acd-9414-e1abad573338.png)

操作系统

windows

Java 版本

java8

wechatpay-java 版本

0.2.1

其他信息

No response

java.lang.IllegalArgumentException: java.security.cert.CertificateException: Could not parse certificate: java.io.IOException: Empty input

错误描述

java.lang.IllegalArgumentException: java.security.cert.CertificateException: Could not parse certificate: java.io.IOException: Empty input
at com.wechat.pay.java.core.util.PemUtil.loadX509FromStream(PemUtil.java:114)
at com.wechat.pay.java.core.util.PemUtil.loadX509FromString(PemUtil.java:172)
at com.wechat.pay.java.core.notification.RSANotificationConfig$Builder.certificates(RSANotificationConfig.java:64)
at com.mineway.crm.service.pay.WxPayService.getDecryptObject(WxPayService.java:139)
at com.mineway.crm.service.impl.OrderServiceImpl.payNotify(OrderServiceImpl.java:276)

重现bug的步骤

java.lang.IllegalArgumentException: java.security.cert.CertificateException: Could not parse certificate: java.io.IOException: Empty input
at com.wechat.pay.java.core.util.PemUtil.loadX509FromStream(PemUtil.java:114)
at com.wechat.pay.java.core.util.PemUtil.loadX509FromString(PemUtil.java:172)
at com.wechat.pay.java.core.notification.RSANotificationConfig$Builder.certificates(RSANotificationConfig.java:64)
at com.mineway.crm.service.pay.WxPayService.getDecryptObject(WxPayService.java:139)
at com.mineway.crm.service.impl.OrderServiceImpl.payNotify(OrderServiceImpl.java:276)

预期行为

java.lang.IllegalArgumentException: java.security.cert.CertificateException: Could not parse certificate: java.io.IOException: Empty input
at com.wechat.pay.java.core.util.PemUtil.loadX509FromStream(PemUtil.java:114)
at com.wechat.pay.java.core.util.PemUtil.loadX509FromString(PemUtil.java:172)
at com.wechat.pay.java.core.notification.RSANotificationConfig$Builder.certificates(RSANotificationConfig.java:64)
at com.mineway.crm.service.pay.WxPayService.getDecryptObject(WxPayService.java:139)
at com.mineway.crm.service.impl.OrderServiceImpl.payNotify(OrderServiceImpl.java:276)

导致错误的代码片段

No response

操作系统

macOS

Java 版本

Java8

wechatpay-java 版本

0.2.2

其他信息

No response

关于SDK优化的几个建议

wecom-temp-119762-4ebfcce96d5ddd08d5ce4328a9579411

1. 对上传的文件大小是否有限制?如果没有,建议采用缓冲 buffer 流式写到 request body 里,不要直接设置整个 file 的字节数组进去,否则上传大文件可能导致服务端就 OOM。


wecom-temp-129110-6f3d74476166cbf417b1183285a8a581
2. GsonUtil 这里的 gsonBuilder 是单例,但是 Gson 对象不是单例,每次都会创建一个新的 Gson 对象。


wecom-temp-324856-cdb1d7f9d9fa2677eb99c4b27b059f58
3. out_trade_no 需要做下 url encode,这里要看下 httpclient 有没有帮你做了这个操作。商户支付的订单号由商户自定义生成,仅支持使用字母、数字、中划线-、下划线_、竖线|、星号这些英文半角字符的组合,abcd1234-_| encode 的结果是 abcd1234-_%7C%2A。


wecom-temp-219046-c7e91a5b9614b7406622da4221105a3b
4. ACCEPT 的 header 应该是指定 json,这里只会返回 json,为什么设置“/”?


wecom-temp-287563-6d1096a481293db5eb447c9eb3e5d46b
5. 这里是不支持泛型类的,这里如果有类似 class PrepayResponse 这种类的时候,反序列化是会失败的。


wecom-temp-239562-15c413537d124afc02ef7120af62ea5c
6. 这类接口你给用户的感觉就是不会抛任何异常,但其实你的这些代码有抛 RuntimeException 的风险,你需要把这个暴露出来,告诉用户这个接口会抛异常,让用户有感知,以便他自己决策是否需要处理。

wechatpay-apiv3:wechatpay-java-core:0.2.4 这个包还没有上传吗?

错误描述

wechatpay-apiv3:wechatpay-java-core:0.2.4 这个包还没有上传吗?
image

重现bug的步骤

wechatpay-apiv3:wechatpay-java-core:0.2.4 这个包还没有上传吗?
image

预期行为

希望可以顺利拉取最新的jar

导致错误的代码片段

No response

操作系统

win

Java 版本

8

wechatpay-java 版本

0.2.4

其他信息

No response

java.lang.NoSuchMethodError: 'okhttp3.RequestBody

错误描述

java.lang.NoSuchMethodError: 'okhttp3.RequestBody okhttp3.RequestBody.create(java.lang.String, okhttp3.MediaType)'
at com.wechat.pay.java.core.http.okhttp.OkHttpClientAdapter.createOkHttpRequestBody(OkHttpClientAdapter.java:84) ~[wechatpay-java-core-0.2.0.jar:0.2.0]
at com.wechat.pay.java.core.http.okhttp.OkHttpClientAdapter.buildOkHttpRequestBody(OkHttpClientAdapter.java:70) ~[wechatpay-java-core-0.2.0.jar:0.2.0]
at com.wechat.pay.java.core.http.okhttp.OkHttpClientAdapter.buildOkHttpRequest(OkHttpClientAdapter.java:59) ~[wechatpay-java-core-0.2.0.jar:0.2.0]
at com.wechat.pay.java.core.http.okhttp.OkHttpClientAdapter.innerExecute(OkHttpClientAdapter.java:46) ~[wechatpay-java-core-0.2.0.jar:0.2.0]
at com.wechat.pay.java.core.http.AbstractHttpClient.execute(AbstractHttpClient.java:42) ~[wechatpay-java-core-0.2.0.jar:0.2.0]
at com.wechat.pay.java.service.payments.jsapi.JsapiService.prepay(JsapiService.java:162) ~[wechatpay-java-0.2.0.jar:0.2.0]

重现bug的步骤

根据示例代码调用预下单接口

预期行为

完成下单

导致错误的代码片段

No response

操作系统

macOS

Java 版本

Java 17

wechatpay-java 版本

0.2.1

其他信息

No response

Validate response failed,the WechatPay signature is incorrect.

错误描述

Exception in thread "main" com.wechat.pay.java.core.exception.ValidationException: Validate response failed,the WechatPay signature is incorrect.

重现bug的步骤

Exception in thread "main" com.wechat.pay.java.core.exception.ValidationException: Validate response failed,the WechatPay signature is incorrect.

预期行为

Exception in thread "main" com.wechat.pay.java.core.exception.ValidationException: Validate response failed,the WechatPay signature is incorrect.

导致错误的代码片段

No response

操作系统

macos

Java 版本

8

wechatpay-java 版本

0.2.1

其他信息

No response

validateResponse 异常

错误描述

Validate response failed,the WechatPay signature is incorrect.

重现bug的步骤

Exception in thread "main" com.wechat.pay.java.core.exception.ValidationException: Validate response failed,the WechatPay signature is incorrect.
at com.wechat.pay.java.core.http.AbstractHttpClient.validateResponse(AbstractHttpClient.java:70)
at com.wechat.pay.java.core.http.AbstractHttpClient.execute(AbstractHttpClient.java:43)
at com.wechat.pay.java.service.payments.jsapi.JsapiService.prepay(JsapiService.java:162)
at com.mineway.crm.zx.pay.WxPay.main(WxPay.java:50)
Disconnected from the target VM, address: '127.0.0.1:62376', transport: 'socket'

预期行为

Exception in thread "main" com.wechat.pay.java.core.exception.ValidationException: Validate response failed,the WechatPay signature is incorrect.
at com.wechat.pay.java.core.http.AbstractHttpClient.validateResponse(AbstractHttpClient.java:70)
at com.wechat.pay.java.core.http.AbstractHttpClient.execute(AbstractHttpClient.java:43)
at com.wechat.pay.java.service.payments.jsapi.JsapiService.prepay(JsapiService.java:162)
at com.mineway.crm.zx.pay.WxPay.main(WxPay.java:50)
Disconnected from the target VM, address: '127.0.0.1:62376', transport: 'socket'

导致错误的代码片段

No response

操作系统

macos

Java 版本

8

wechatpay-java 版本

0.2.1

其他信息

No response

微信收款商业版的订单如何查询

您的功能请求与问题有关吗? 请描述您遇到的问题

如图所示,这种订单无法查询。

image

使用的是NativePayService

/**
 * 微信支付订单号查询订单
 */
public static Transaction queryOrderById() {

    QueryOrderByIdRequest request = new QueryOrderByIdRequest();
    // 调用request.setXxx(val)设置所需参数,具体参数可见Request定义
    // 调用接口
    request.setSpMchid("");
    request.setSubMchid("");
    request.setTransactionId("");
    return service.queryOrderById(request);
}

请求返回

{"code":"PARAM_ERROR","message":"普通商户不允许传sub_mch_id"}

描述您想要的解决方案

No response

您还有其他的方案吗?

No response

其他信息

No response

预支付自动更新平台证书 解密失败

错误描述

预支付自动更新平台证书 解密失败
微信图片_20221227123210

重现bug的步骤

预支付自动更新平台证书 解密失败

预期行为

预支付自动更新平台证书 解密失败

导致错误的代码片段

No response

操作系统

windows

Java 版本

Java1.8.0_221

wechatpay-java 版本

master分支

其他信息

No response

微信小程序支付,回调通知,官方提供api和示例有出入

错误描述

微信小程序支付,回调通知,官方提供api和示例有出入

重现bug的步骤

  1. 这是你们的示例
    微信图片_20221228170016
  2. 这是代码中要传的参数
    微信图片_20221228170146

这两个根本对不上呀,是两个类,你看看我需要在NotificationParser的构造方法中传什么参数?

预期行为

看看我需要在NotificationParser的构造方法中传什么参数?

导致错误的代码片段

No response

操作系统

win

Java 版本

8

wechatpay-java 版本

0.2.3

其他信息

No response

Canceled

您的功能请求与问题有关吗? 请描述您遇到的问题

No response

描述您想要的解决方案

No response

您还有其他的方案吗?

No response

其他信息

No response

Validate response failed,the WechatPay signature is incorrect.

错误描述

我使用 JsapiServiceExtensionExample 中的代码,提示:Validate response failed,the WechatPay signature is incorrect.
代码中有句注释:
// 使用 com.wechat.pay.java.core.util 中的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名
.privateKeyFromPath()
但是:privateKeyFromPath() 方法的参数是 String,私钥的路径。而 PemUtil 工具类的方法,是加载私钥。这是什么意思?重复了?

重现bug的步骤

1.直接用你们的代码就能复现

预期行为

至少用你们的示例代码能下单吧

导致错误的代码片段

// 初始化商户配置
    RSAConfig config =
        new RSAConfig.Builder()
            .merchantId(merchantId)
            // 使用 com.wechat.pay.java.core.util 中的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名
            .privateKeyFromPath(privateKeyPath)
            .merchantSerialNumber(merchantSerialNumber)
            .wechatPayCertificatesFromPath(wechatPayCertificatePath)
            .build();

操作系统

macOS

Java 版本

java1.8

wechatpay-java 版本

0.2.2

其他信息

用SDK,不是不用自己签名吗?

自动更新平台证书

您的功能请求与问题有关吗? 请描述您遇到的问题

提供自动更新平台证书能力,使用者不用传入平台证书。

描述您想要的解决方案

修改点

  1. 增加 autoUpdateCertificateProvider,实现 CertificateProvider。
  2. 修改 RSAConfig 的 Builder,如果不传 wechatPayCertificate,RSAConfig中的构造器传入 autoUpdateCertificateProvider。

实现细节

  1. 封装安全单例线程池 SafeSingleScheduleExecutor。
  2. autoUpdateCertificateProvider 中使用单例线程池 SafeSingleScheduleExecutor ,用于定时下载更新证书。
  3. 使用原生的 okhttp 请求来下载证书。

您还有其他的方案吗?

No response

其他信息

No response

能否对wechatpay-apache-httpclient进行兼容

您的功能请求与问题有关吗? 请描述您遇到的问题

我们目前使用了wechatpay-apache-httpclient并实现了部分接口,现在想用wechatpay-java去实现图片视频上传。但是发现并不兼容,需要重复初始化配置。

描述您想要的解决方案

能否对wechatpay-apache-httpclient进行兼容,或者反过来也行。如果不能兼容,也能否给出一个能平滑迁移的代码实例,方便使用方去调用。

您还有其他的方案吗?

No response

其他信息

No response

金额不支持小数点吗

您的功能请求与问题有关吗? 请描述您遇到的问题

Amount amount = new Amount();
amount.setTotal(); // 这里接收的是Integer

描述您想要的解决方案

如果我想设置带小数点的金额怎么办?

您还有其他的方案吗?

No response

其他信息

No response

wechatpay-java 调用nativePay支付接口报错

错误描述

我用的版本是:
image
调用的接口是:
image
我跟进去看了是:
image
image
看起来参数的顺序都不对。
请问,我的是不是不是最新版本的wechatpay-java呀?
image
现在该怎么办呢?

重现bug的步骤

如上

预期行为

如上

导致错误的代码片段

No response

操作系统

windows

Java 版本

java 17

wechatpay-java 版本

0.2.0

其他信息

如上

V3版本的POST无参数请求会一直报错

错误描述

解约接口:/v3/offlinefacemch/organizations/{organization_id}/users/user-id/{user_id}/terminate-contract,文档要求不需要参数,参考文档,使用api中的httpClient请求是一直提示请求的参数错误,其他接口请求都正常,唯独这个无参的POST请求不同,接口参考地址:https://pay.weixin.qq.com/wiki/doc/wxfacepay/develop/k12-development-guidelines.html#_4-6-%E8%A7%A3%E9%99%A4%E5%88%B7%E8%84%B8%E7%94%A8%E6%88%B7%E7%AD%BE%E7%BA%A6%E5%85%B3%E7%B3%BB%E6%8E%A5%E5%8F%A3

重现bug的步骤

image
这个是代码,参数为空,一直提示参数有误

预期行为

正常执行接口请求

导致错误的代码片段

No response

操作系统

windows

Java 版本

java11

wechatpay-java 版本

0.2.0

其他信息

No response

修改model中的toString方式

您的功能请求与问题有关吗? 请描述您遇到的问题

现在model中的toString方法为

  @Override
  public String toString() {
    return GsonUtil.getGson().toJson(this);
  }

使用了SDK中的GsonUtil中得到的gson,会忽略某些字段,无法打印model中的所有字段。

描述您想要的解决方案

修改成能打印出所有的字段。

您还有其他的方案吗?

No response

其他信息

No response

自动下载的证书使用场景?

您的功能请求与问题有关吗? 请描述您遇到的问题

自动下载的证书干嘛用的?能举个例子吗?是否还需要定期调用自动下载续期?
感觉微信支付真的是乱七八糟,这些写sdk都不知道自己有没有从头到尾接过。学习一下支付宝?

描述您想要的解决方案

No response

您还有其他的方案吗?

No response

其他信息

No response

支付结果通知验签失败

错误描述

以下为参考示例验证签名的代码
源码

重现bug的步骤

下面是报错信息:
2022-12-11 15:28:51.370 DEBUG 742001 --- [nio-8080-exec-6] o.s.web.servlet.DispatcherServlet : Failed to complete request: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at line 1 column 2 path $
2022-12-11 15:28:51.372 ERROR 742001 --- [nio-8080-exec-6] o.a.c.c.C.[.[.[.[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [/payment] threw exception [Request processing failed; nested exception is com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at line 1 column 2 path $] with root cause

java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at line 1 column 2 path $
at com.google.gson.stream.JsonReader.nextString(JsonReader.java:825) ~[gson-2.9.0.jar!/:na]
at com.google.gson.internal.bind.TypeAdapters$15.read(TypeAdapters.java:393) ~[gson-2.9.0.jar!/:na]
at com.google.gson.internal.bind.TypeAdapters$15.read(TypeAdapters.java:381) ~[gson-2.9.0.jar!/:na]
at com.google.gson.Gson.fromJson(Gson.java:991) ~[gson-2.9.0.jar!/:na]
at com.google.gson.Gson.fromJson(Gson.java:956) ~[gson-2.9.0.jar!/:na]
at com.google.gson.Gson.fromJson(Gson.java:905) ~[gson-2.9.0.jar!/:na]
at com.google.gson.Gson.fromJson(Gson.java:876) ~[gson-2.9.0.jar!/:na]
at com.wechat.pay.java.core.notification.NotificationParser.getDecryptObject(NotificationParser.java:111) ~[wechatpay-java-core-0.2.1.jar!/:0.2.1]
at com.wechat.pay.java.core.notification.NotificationParser.parse(NotificationParser.java:50) ~[wechatpay-java-core-0.2.1.jar!/:0.2.1]
at cn.moshaw.payment.weichat.service.WechatpayService.virifyCallBackSignature(WechatpayService.java:341) ~[classes!/:0.0.1-SNAPSHOT]
at cn.moshaw.payment.weichat.controller.WxCallbackController.callback(WxCallbackController.java:62) ~[classes!/:0.0.1-SNAPSHOT]
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:578) ~[na:na]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-5.3.22.jar!/:5.3.22]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) ~[spring-web-5.3.22.jar!/:5.3.22]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) ~[spring-webmvc-5.3.22.jar!/:5.3.22]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) ~[spring-webmvc-5.3.22.jar!/:5.3.22]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-5.3.22.jar!/:5.3.22]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.22.jar!/:5.3.22]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1070) ~[spring-webmvc-5.3.22.jar!/:5.3.22]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) ~[spring-webmvc-5.3.22.jar!/:5.3.22]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.22.jar!/:5.3.22]
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) ~[spring-webmvc-5.3.22.jar!/:5.3.22]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:681) ~[tomcat-embed-core-9.0.65.jar!/:na]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.3.22.jar!/:5.3.22]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:764) ~[tomcat-embed-core-9.0.65.jar!/:na]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) ~[tomcat-embed-core-9.0.65.jar!/:na]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.65.jar!/:na]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.65.jar!/:na]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.65.jar!/:na]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.65.jar!/:na]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.3.22.jar!/:5.3.22]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.22.jar!/:5.3.22]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.65.jar!/:na]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.65.jar!/:na]
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.3.22.jar!/:5.3.22]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.22.jar!/:5.3.22]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.65.jar!/:na]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.65.jar!/:na]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.3.22.jar!/:5.3.22]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.22.jar!/:5.3.22]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.65.jar!/:na]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.65.jar!/:na]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) ~[tomcat-embed-core-9.0.65.jar!/:na]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) ~[tomcat-embed-core-9.0.65.jar!/:na]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) ~[tomcat-embed-core-9.0.65.jar!/:na]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) ~[tomcat-embed-core-9.0.65.jar!/:na]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-9.0.65.jar!/:na]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) ~[tomcat-embed-core-9.0.65.jar!/:na]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360) ~[tomcat-embed-core-9.0.65.jar!/:na]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399) ~[tomcat-embed-core-9.0.65.jar!/:na]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-9.0.65.jar!/:na]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:890) ~[tomcat-embed-core-9.0.65.jar!/:na]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1789) ~[tomcat-embed-core-9.0.65.jar!/:na]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.65.jar!/:na]
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[tomcat-embed-core-9.0.65.jar!/:na]
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-9.0.65.jar!/:na]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.65.jar!/:na]
at java.base/java.lang.Thread.run(Thread.java:1589) ~[na:na]

预期行为

不知代码哪里有问题,该如何调整?

导致错误的代码片段

No response

操作系统

macOS

Java 版本

Java 17

wechatpay-java 版本

0.2.1

其他信息

No response

微信文档稀烂

您的功能请求与问题有关吗? 请描述您遇到的问题

为什么每次需要的证书在哪里获取总是不说明?以前如此,现在还是如此

描述您想要的解决方案

No response

您还有其他的方案吗?

No response

其他信息

No response

CertificateServiceExample跑不通

错误描述

获取平台证书列表接口不需要验签

没有跳过验签的配置

重现bug的步骤

  • com.wechat.pay.java.core.RSAConfig 要求配置公钥
  • com.wechat.pay.java.core.http.AbstractHttpClient 默认验签

预期行为

期望支持跳过验签

导致错误的代码片段

No response

操作系统

macOS

Java 版本

Java 18

wechatpay-java 版本

main 303a8ad

其他信息

No response

下载证书能默认把验签去掉吗?或者给个开关,恶心的一批

您的功能请求与问题有关吗? 请描述您遇到的问题

你们要是真的为安全着想,请完善sdk,让上层应用透明使用,封装都不知道吗?搞的什么玩意。
就算我第一次把证书通过jar下载下来了,配置在了配置文件(本地或者etcd)里,我更新证书的时候还要去改这他们?如果不改,一旦失效,新的证书就下载不下来了。而且你们提供的默认下载在内存里,重启后不还是老证书在验签,总有一天他们会不能用,不是嘛。

描述您想要的解决方案

证书完全内存化,对上层业务透明,第一次下载证书无需验证。
就像https协议一样,请sdk自行实现续约,不要垃圾搞一半,拿出点水准来?

您还有其他的方案吗?

No response

其他信息

No response

使用SDK,Exception in thread "main" com.wechat.pay.java.core.exception.ValidationException: Validate response failed,the WechatPay signature is incorrect.

错误描述

Exception in thread "main" com.wechat.pay.java.core.exception.ValidationException: Validate response failed,the WechatPay signature is incorrect.

重现bug的步骤

1、使用Demo中的例子;
2、配置好所有参数后发起:下载微信支付平台证书
3、返回签名失败错误;

预期行为

SDK的签名不正确

导致错误的代码片段

No response

操作系统

windows

Java 版本

Java 17

wechatpay-java 版本

v0.2.0

其他信息

No response

createOkHttpRequestBody 异常

错误描述

java.lang.NoSuchMethodError: okhttp3.RequestBody.create(Ljava/lang/String;Lokhttp3/MediaType;)Lokhttp3/RequestBody;

重现bug的步骤

createOkHttpRequestBody 异常

预期行为

createOkHttpRequestBody 异常

导致错误的代码片段

No response

操作系统

macos

Java 版本

java 8

wechatpay-java 版本

0.2.1

其他信息

No response

jsapipay 前端小程序需要的签名如何生成

您的功能请求与问题有关吗? 请描述您遇到的问题

jsapipay 前端小程序需要的签名如何生成

描述您想要的解决方案

No response

您还有其他的方案吗?

No response

其他信息

No response

baseUrl 支持

您的功能请求与问题有关吗? 请描述您遇到的问题

除了 api.mch.weixin.qq.com 之外,还有 apihk 的域名,应允许开发者指定。

描述您想要的解决方案

Config 中增加 baseUrl 的配置项,在 service 中使用 baseUrl + Path 的方式访问 API。

您还有其他的方案吗?

No response

其他信息

No response

使用DefaultHttpClientBuilder构造出来的HttpClient需要关闭吗?

您的功能请求与问题有关吗? 请描述您遇到的问题

请问使用以下代码获取的HttpClient实例需要触发关闭吗?我看这个HttpClient接口里没有close方法呢?

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

HttpClient httpClient = new DefaultHttpClientBuilder()
.readTimeoutMs(3000)
.writeTimeoutMs(3000)
.connectTimeoutMs(3000)
.credential(requireNonNull(config.createCredential()))
.validator(requireNonNull(config.createValidator()))
.build();

maven依赖如下:
image

描述您想要的解决方案

您还有其他的方案吗?

其他信息

验签失败

错误描述

Validate response failed,the WechatPay signature is incorrect.
↵Request-ID[08A8AAAB9A0610D10718E8C5C05520A5B00D2880EE03-0] responseHeader[Keep-Alive=timeout=8,Wechatpay-Timestamp=1665848617,Server=nginx,X-Content-Type-Options=nosniff,Connection=keep-alive,Date=Sat, 15 Oct 2022 15:43:37 GMT,Wechatpay-Signature-Type=WECHATPAY2-SHA256-RSA2048,Wechatpay-Serial=6A79D4EC075AD126ED5D20E925507117F5F0C8FA,Wechatpay-Nonce=0a5ccb1cfb2add2f751351f363c1ead1,Wechatpay-Signature=o+YfoCHERSItpuezH4Lgo9QotjIW/9mGoh0KSkDvPHQtAsnE8NGysDJDB4oR4LZeMTozCjpkBhvtuxkdLXghKwH5G0/V6PrqvPBtPopNpoNVlU1dDgMXWaDNng0gLqgxdEFVT4N7fWOy/NfyKDn2IFQdAIzlGdrs/xre2y5oVkUrwu54SSHUWwc0srDEGRQZA7eZS5sitJLCYozjt6UiGrbcak39iqVAP5xKojqjY1BCIqKavgNKg1JRB765IGcxQlae5nwSyVPOHBUUkbwWY+DLgd6VHkT+Crc0JimCX1B8MjWfwa3amC0lW/hpTGf0+LCI9FB1qj8AJEd0ladFhA==,Cache-Control=no-cache, must-revalidate,Content-Length=52,Request-ID=08A8AAAB9A0610D10718E8C5C05520A5B00D2880EE03-0,Content-Language=zh-CN,Content-Type=application/json; charset=utf-8↵] responseBody[{"prepay_id":"wx15234337156985c7708abc64fd7e610000"}]"

重现bug的步骤

Validate response failed,the WechatPay signature is incorrect.
↵Request-ID[08A8AAAB9A0610D10718E8C5C05520A5B00D2880EE03-0] responseHeader[Keep-Alive=timeout=8,Wechatpay-Timestamp=1665848617,Server=nginx,X-Content-Type-Options=nosniff,Connection=keep-alive,Date=Sat, 15 Oct 2022 15:43:37 GMT,Wechatpay-Signature-Type=WECHATPAY2-SHA256-RSA2048,Wechatpay-Serial=6A79D4EC075AD126ED5D20E925507117F5F0C8FA,Wechatpay-Nonce=0a5ccb1cfb2add2f751351f363c1ead1,Wechatpay-Signature=o+YfoCHERSItpuezH4Lgo9QotjIW/9mGoh0KSkDvPHQtAsnE8NGysDJDB4oR4LZeMTozCjpkBhvtuxkdLXghKwH5G0/V6PrqvPBtPopNpoNVlU1dDgMXWaDNng0gLqgxdEFVT4N7fWOy/NfyKDn2IFQdAIzlGdrs/xre2y5oVkUrwu54SSHUWwc0srDEGRQZA7eZS5sitJLCYozjt6UiGrbcak39iqVAP5xKojqjY1BCIqKavgNKg1JRB765IGcxQlae5nwSyVPOHBUUkbwWY+DLgd6VHkT+Crc0JimCX1B8MjWfwa3amC0lW/hpTGf0+LCI9FB1qj8AJEd0ladFhA==,Cache-Control=no-cache, must-revalidate,Content-Length=52,Request-ID=08A8AAAB9A0610D10718E8C5C05520A5B00D2880EE03-0,Content-Language=zh-CN,Content-Type=application/json; charset=utf-8↵] responseBody[{"prepay_id":"wx15234337156985c7708abc64fd7e610000"}]"

预期行为

验签通过

导致错误的代码片段

No response

操作系统

win10

Java 版本

java8

wechatpay-java 版本

0.2.0

其他信息

Validate response failed,the WechatPay signature is incorrect.
↵Request-ID[08A8AAAB9A0610D10718E8C5C05520A5B00D2880EE03-0] responseHeader[Keep-Alive=timeout=8,Wechatpay-Timestamp=1665848617,Server=nginx,X-Content-Type-Options=nosniff,Connection=keep-alive,Date=Sat, 15 Oct 2022 15:43:37 GMT,Wechatpay-Signature-Type=WECHATPAY2-SHA256-RSA2048,Wechatpay-Serial=6A79D4EC075AD126ED5D20E925507117F5F0C8FA,Wechatpay-Nonce=0a5ccb1cfb2add2f751351f363c1ead1,Wechatpay-Signature=o+YfoCHERSItpuezH4Lgo9QotjIW/9mGoh0KSkDvPHQtAsnE8NGysDJDB4oR4LZeMTozCjpkBhvtuxkdLXghKwH5G0/V6PrqvPBtPopNpoNVlU1dDgMXWaDNng0gLqgxdEFVT4N7fWOy/NfyKDn2IFQdAIzlGdrs/xre2y5oVkUrwu54SSHUWwc0srDEGRQZA7eZS5sitJLCYozjt6UiGrbcak39iqVAP5xKojqjY1BCIqKavgNKg1JRB765IGcxQlae5nwSyVPOHBUUkbwWY+DLgd6VHkT+Crc0JimCX1B8MjWfwa3amC0lW/hpTGf0+LCI9FB1qj8AJEd0ladFhA==,Cache-Control=no-cache, must-revalidate,Content-Length=52,Request-ID=08A8AAAB9A0610D10718E8C5C05520A5B00D2880EE03-0,Content-Language=zh-CN,Content-Type=application/json; charset=utf-8↵] responseBody[{"prepay_id":"wx15234337156985c7708abc64fd7e610000"}]"

jsapi service提供新的prepay函数,支持生成getBrandWCPayRequest参数

您的功能请求与问题有关吗? 请描述您遇到的问题

既然getBrandWCPayRequest的参数需要商户私钥签名,为什么不直接返回签名后的参数。

仅仅是为了与前端隔离吗?

描述您想要的解决方案

jsapi service提供新的prepay函数,支持生成getBrandWCPayRequest参数。

您还有其他的方案吗?

No response

其他信息

No response

商户号初始化配置重复,下载任务报错。

错误描述

image
image
商户号初始化配置重复,下载任务报错。

重现bug的步骤

启动项目测试初始化配置后,重复下载任务报错问题怎么解决,还没有存到redis中。现在生成不了配置了。

预期行为

正常初始化商户号配置

导致错误的代码片段

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

操作系统

window

Java 版本

java 8

wechatpay-java 版本

v0.2.3

其他信息

No response

Handler dispatch failed; nested exception is java.lang.NoSuchMethodError: okhttp3.RequestBody.create(Ljava/lang/String;Lokhttp3/MediaType;)Lokhttp3/RequestBody;

错误描述

在maven中引入0.2.1版本后执行报错,
bug发生在com.wechat.pay.java.core.http.okhttp.OkHttpClientAdapter类里面,该类中执行createOkHttpRequestBody 方法时调用了 okhttp3.RequestBody.create(MediaType contentType, String content),但是参数写反了,导致报错

重现bug的步骤

private RequestBody createOkHttpRequestBody(
com.wechat.pay.java.core.http.RequestBody wechatPayRequestBody) {
return okhttp3.RequestBody.create(
((JsonRequestBody) wechatPayRequestBody).getBody(),
okhttp3.MediaType.parse(wechatPayRequestBody.getContentType()));
}

private RequestBody createOkHttpMultipartRequestBody(
com.wechat.pay.java.core.http.RequestBody wechatPayRequestBody) {
FileRequestBody fileRequestBody = (FileRequestBody) wechatPayRequestBody;
okhttp3.RequestBody okHttpFileBody =
okhttp3.RequestBody.create(
fileRequestBody.getFile(), okhttp3.MediaType.parse(fileRequestBody.getContentType()));
return new okhttp3.MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart(META_NAME, fileRequestBody.getMeta())
.addFormDataPart(FILE_NAME, fileRequestBody.getFileName(), okHttpFileBody)
.build();
}

预期行为

Caused by: java.lang.NoSuchMethodError: okhttp3.RequestBody.create(Ljava/lang/String;Lokhttp3/MediaType;)Lokhttp3/RequestBody;
at com.wechat.pay.java.core.http.okhttp.OkHttpClientAdapter.createOkHttpRequestBody(OkHttpClientAdapter.java:84) ~[wechatpay-java-core-0.2.1.jar:0.2.1]
at com.wechat.pay.java.core.http.okhttp.OkHttpClientAdapter.buildOkHttpRequestBody(OkHttpClientAdapter.java:70) ~[wechatpay-java-core-0.2.1.jar:0.2.1]
at com.wechat.pay.java.core.http.okhttp.OkHttpClientAdapter.buildOkHttpRequest(OkHttpClientAdapter.java:59) ~[wechatpay-java-core-0.2.1.jar:0.2.1]
at com.wechat.pay.java.core.http.okhttp.OkHttpClientAdapter.innerExecute(OkHttpClientAdapter.java:46) ~[wechatpay-java-core-0.2.1.jar:0.2.1]
at com.wechat.pay.java.core.http.AbstractHttpClient.execute(AbstractHttpClient.java:42) ~[wechatpay-java-core-0.2.1.jar:0.2.1]
at com.wechat.pay.java.service.payments.nativepay.NativePayService.prepay(NativePayService.java:162) ~[wechatpay-java-0.2.1.jar:0.2.1]

导致错误的代码片段

No response

操作系统

Windows

Java 版本

java 8

wechatpay-java 版本

0.2.1

其他信息

No response

能完善下APP下单之类的示例吗?

比如AppServiceExample
能完善下吗?

 // 初始化商户配置
 RSAConfig config =
        new RSAConfig.Builder()
            .merchantId(merchantId)
            // 使用 com.wechat.pay.java.core.util
            // 中的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名
            .privateKeyFromPath(privateKeyPath)
            .merchantSerialNumber(merchantSerialNumber)
            .wechatPayCertificatesFromPath(wechatPayCertificatePath)
            .build();

// 初始化服务
service = new AppService.Builder().config(config).build();

// ... 调用接口
Amount amount = new Amount();
            amount.setTotal(1);
            amount.setCurrency("CNY");
            PrepayRequest request = new PrepayRequest();
            request.setAppid(WEBCHAT_PAY_APP_ID);
            request.setMchid("1630408924");
            request.setDescription("测试商品标题");
            request.setNotifyUrl(BASE_URL);
            request.setOutTradeNo("1101000000140429eb40476f8896f4c9");
            request.setAmount(amount);

service.prepay(request);

APP支付下单之后,我想返回获取返回的prepay_id该怎么办?没反应。
还有不用验签吗?

No response

sdk中的接口与官方文档的接口不符

您的功能请求与问题有关吗? 请描述您遇到的问题

https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1 这个是jsapi的接口文档
这个是sdk 中的https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi 接口,这个在官方文档中都没搜到这个接口

com.github.wechatpay-apiv3
wechatpay-java
0.2.2

描述您想要的解决方案

与官方的接口文档对齐

您还有其他的方案吗?

No response

其他信息

No response

商家转账到零钱,如果超出免密额度,出资商户在商家助手进行付款确认后,有机制通知到商家后端吗?

您的功能请求与问题有关吗? 请描述您遇到的问题

在调用【通过商家批次单号查询批次单】接口时发现返回值里的batch_status字段有一个【WAIT_PAY】值,说明是“需要付款出资商户在商家助手小程序或服务商助手小程序进行付款确认”,但是这个确认的动作是线下的,一般也是老板或者领导进行确认,作为技术人员无法确定这个时间,就无法再在某个时间点再次触发查询批次单状态了。

描述您想要的解决方案

能否在出资商户进行付款确认后,主动通知一下商户后端,这样就可以再次查询批次单状态进而进行后续的业务逻辑处理了。

您还有其他的方案吗?

No response

其他信息

No response

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.