Skip to content

修复:代理转发场景下微信支付 V3 API Authorization 头丢失导致 401#3910

Open
Copilot wants to merge 2 commits intodevelopfrom
copilot/fix-wechat-request-forwarding
Open

修复:代理转发场景下微信支付 V3 API Authorization 头丢失导致 401#3910
Copilot wants to merge 2 commits intodevelopfrom
copilot/fix-wechat-request-forwarding

Conversation

Copy link
Contributor

Copilot AI commented Mar 7, 2026

当用户将 apiHostUrl(或 payBaseUrl)配置为内部反向代理地址时,SignatureExec 仅对以 .mch.weixin.qq.com 结尾的主机添加 Authorization 头,导致转发请求缺少认证信息,微信返回 401。

变更

  • SignatureExec:新增 trustedHosts: Set<String> 字段;execute() 在主机名匹配受信任列表时也执行签名逻辑;旧三参数构造函数保持向后兼容
  • WxPayV3HttpClientBuilder:新增 withTrustedHost(String host) 链式方法,允许手动注册受信任主机
  • WxPayConfig.initApiV3HttpClient():自动解析 apiHostUrl,若为非微信官方主机则注册为受信任主机
  • AutoUpdateCertificatesVerifier.autoUpdateCert():同上,自动处理 payBaseUrl 中的自定义代理主机

配置了自定义 apiHostUrl 后,无需额外代码,SDK 自动将代理主机加入受信任列表:

WxPayConfig config = new WxPayConfig();
config.setApiHostUrl("http://proxy.company.com:8080"); // 自动注册为受信任主机
// 此后所有 V3 请求(含 /v3/certificates)发往代理时均携带 Authorization 头

如需手动控制,也可通过 builder 显式添加:

WxPayV3HttpClientBuilder.create()
    .withMerchant(mchId, serialNo, privateKey)
    .withValidator(validator)
    .withTrustedHost("proxy.company.com")
    .build();
Original prompt

This section details on the original issue you should resolve

<issue_title>不能直连微信的,要怎么配置转发请求</issue_title>
<issue_description>使用了jar包里的多商户配置,通过swichcover接口切换,调用wxPayService.createOrderV3接口发起支付,在支付之前包里集成调用了/v3/certificates接口,config配置payBaseUrl(4.7),apiHostUrl(4.8),但是转发都不行,转发过去的请求头里Authorization不见了,微信返回401,要如何正确配置才能通过转发到代理ng,再调用微信</issue_description>

Comments on the Issue (you are @copilot in this section)

Custom agent used: 全部用中文
需要用中文,包括PR标题和分析总结过程


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Co-authored-by: binarywang <1343140+binarywang@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix configuration for forwarding WeChat requests 修复:代理转发场景下微信支付 V3 API Authorization 头丢失导致 401 Mar 7, 2026
@binarywang binarywang marked this pull request as ready for review March 7, 2026 10:42
Copilot AI review requested due to automatic review settings March 7, 2026 10:42
@augmentcode
Copy link

augmentcode bot commented Mar 7, 2026

🤖 Augment PR Summary

Summary: 本 PR 修复了在“通过内网反向代理转发微信支付 V3 API”场景下,请求未携带 Authorization 头而导致微信侧返回 401 的问题。

Changes:

  • 扩展 SignatureExec:新增 trustedHosts(受信任主机集合),对受信任主机也执行签名并添加 Authorization 头;保留旧构造函数以保持兼容。
  • 扩展 WxPayV3HttpClientBuilder:新增 withTrustedHost(String) 链式 API,允许显式注册代理主机。
  • 更新 WxPayConfig.initApiV3HttpClient():自动从 apiHostUrl 解析 host,若非微信官方域名则加入受信任列表。
  • 更新 AutoUpdateCertificatesVerifier.autoUpdateCert():同样从 payBaseUrl 自动注册代理主机,确保拉取平台证书时也携带认证头。
  • 新增单元测试 SignatureExecTrustedHostTest:覆盖官方域名/非受信任代理/受信任代理/兼容旧构造函数等行为。

Technical Notes: 核心策略是“仅对微信官方域名 + 显式/自动注册的代理域名”添加签名头,避免对其他非预期主机发送认证信息。

🤖 Was this summary useful? React with 👍 or 👎

Copy link

@augmentcode augmentcode bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review completed. 2 suggestions posted.

Fix All in Augment

Comment augment review to trigger a new review at any time.

@Override
protected ClientExecChain decorateProtocolExec(final ClientExecChain requestExecutor) {
return new SignatureExec(this.credentials, this.validator, requestExecutor);
return new SignatureExec(this.credentials, this.validator, requestExecutor, this.trustedHosts);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里将可变的 trustedHostsHashSet)引用直接传入 SignatureExec;如果调用方在 build() 之后继续复用/修改 builder,可能在并发请求时引入非线程安全的读写风险(极端情况下会触发 ConcurrentModificationException 或出现可见性问题)。

Severity: medium

Other Locations
  • weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/SignatureExec.java:38

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

String apiHostUrl = this.getApiHostUrl();
if (StringUtils.isNotBlank(apiHostUrl)) {
try {
String host = new URI(apiHostUrl).getHost();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new URI(apiHostUrl).getHost() 只有在 apiHostUrl 为“带 scheme 的绝对 URL”时才能解析出 host;如果用户配置成 proxy.company.com:8080/proxy.company.com(无 scheme),这里会得到 null 导致不会自动加入受信任列表,从而 401 问题仍可能复现。建议在文档或参数校验处明确 apiHostUrl/payBaseUrl 的格式要求。

Severity: low

Other Locations
  • weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/AutoUpdateCertificatesVerifier.java:163

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

该 PR 修复微信支付 V3 在“自定义反向代理域名(apiHostUrl/payBaseUrl)”场景下由于 SignatureExec 仅识别微信官方域名而导致 Authorization 头未被添加、进而请求返回 401 的问题;通过引入“受信任主机列表”机制,使代理域名也能走签名/验签链路。

Changes:

  • SignatureExec 增加 trustedHosts 支持:当请求 host 命中受信任列表时同样添加 Authorization 头并执行验签逻辑(保留旧构造函数)。
  • WxPayV3HttpClientBuilder 增加 withTrustedHost(String host),并在构建时将受信任主机传递给 SignatureExec
  • WxPayConfig.initApiV3HttpClient()AutoUpdateCertificatesVerifier.autoUpdateCert() 中自动从 apiHostUrl/payBaseUrl 解析 host 并加入受信任列表;新增对应单测覆盖代理场景。

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
weixin-java-pay/src/test/java/com/github/binarywang/wxpay/v3/SignatureExecTrustedHostTest.java 新增 trusted host 行为测试,覆盖官方域名/非受信任代理/受信任代理以及旧构造函数兼容性
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/AutoUpdateCertificatesVerifier.java payBaseUrl 自动提取代理 host 并加入受信任列表,确保下载证书请求也带 Authorization
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/WxPayV3HttpClientBuilder.java 引入受信任主机集合与 withTrustedHost API,并将其传入 SignatureExec
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/SignatureExec.java 增加 trusted host 判定分支,命中时执行签名逻辑
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java apiHostUrl 自动解析代理 host 并注册为受信任主机,避免用户额外手工配置

Comment on lines 84 to 87
@Override
protected ClientExecChain decorateProtocolExec(final ClientExecChain requestExecutor) {
return new SignatureExec(this.credentials, this.validator, requestExecutor);
return new SignatureExec(this.credentials, this.validator, requestExecutor, this.trustedHosts);
}
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

decorateProtocolExec() 里把 Builder 内部的 HashSet trustedHosts 直接传给 SignatureExec,会导致 HttpClient 构建完成后仍然持有一个可变、非线程安全的 Set 引用;如果后续继续复用同一个 Builder 调用 withTrustedHost() 或外部并发修改该 Set,可能触发并发问题或行为漂移。建议在这里传入一个不可变的防御性拷贝(例如复制到新的 Set 后再包成 unmodifiable)。

Copilot uses AI. Check for mistakes.
Comment on lines +65 to +69
public WxPayV3HttpClientBuilder withTrustedHost(String host) {
if (host != null && !host.isEmpty()) {
this.trustedHosts.add(host);
}
return this;
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

withTrustedHost(String host) 目前仅判断非空/非空串就直接加入集合,但方法注释要求“主机名(不含端口)”。如果调用方误传入 "proxy.company.com:8080" 或包含前后空格的值,会导致 SignatureExec 匹配不到(因为 URI.getHost() 不含端口),功能表现为“配置了 trusted host 但仍不加 Authorization”。建议在加入前对入参做 trim,并剥离端口(或在检测到包含 scheme/端口时按 URI/Host 规则解析出 host 部分)。

Copilot uses AI. Check for mistakes.
Comment on lines +122 to +131
/**
* 测试:WxPayV3HttpClientBuilder 的 withTrustedHost 方法应该正确设置受信任主机
*/
@Test
public void testWithTrustedHostBuilderMethod() {
WxPayV3HttpClientBuilder builder = WxPayV3HttpClientBuilder.create();
// 方法应该支持链式调用
WxPayV3HttpClientBuilder result = builder.withTrustedHost("proxy.company.com");
assertSame(result, builder, "withTrustedHost 应该返回当前 Builder 实例(支持链式调用)");
}
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

testWithTrustedHostBuilderMethod 的测试名/注释写的是“应该正确设置受信任主机”,但实际只断言了返回值用于链式调用,没有验证 host 确实影响了最终请求的签名行为。建议要么补充断言(例如 build 后发起对 trusted host 的请求并验证 Authorization 头),要么把测试名和注释改成仅验证链式调用,避免测试意图与覆盖范围不一致。

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

不能直连微信的,要怎么配置转发请求

3 participants