You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java通过代理发起Https请求时丢失请求头导致403错误

HttpURLConnection通过代理访问HTTPS API时自定义请求头丢失的问题及解决方法

问题场景

我们需要通过代理访问防火墙外的HTTPS API,使用HttpURLConnection发起请求时,设置的自定义token请求头丢失,目标服务返回403 Forbidden。

配置代码:

static {
    System.setProperty("java.net.useSystemProxies", "true"); // 使用Windows系统代理
    System.setProperty("javax.net.ssl.trustStore", "trust file"); // SSL信任库路径
    System.setProperty("javax.net.ssl.trustStorePassword", "password");// 信任库密码
}

业务代码:

URL obj = new URL(URL);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("GET");
con.setRequestProperty("token","MYTOKEN");
int responseCode = con.getResponseCode(); 

问题原因分析

当调用getResponseCode()触发连接时,DelegateHttpsURLConnection的connect()方法会调用plainConnect(),进而进入代理隧道处理的doTunneling()方法。该方法中存在以下逻辑:

MessageHeader savedRequests = requests;
requests = new MessageHeader();

这段代码会将用户设置的请求头暂存到临时对象(因为这些头不需要发给代理服务器),但后续完成代理隧道连接后,没有把暂存的请求头恢复到原请求中,导致最终发送给目标服务的请求丢失了自定义头。

此前尝试设置-Djdk.http.auth.tunneling.disabledSchemes="",但该参数仅针对Basic认证场景,无法解决自定义请求头丢失的问题。

解决方案

方案1:手动触发隧道连接后重新设置请求头

在调用getResponseCode()之前,先手动触发连接,再重新设置自定义请求头:

URL obj = new URL(URL);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
// 先触发代理隧道连接
con.connect();
// 重新设置自定义请求头和请求方法
con.setRequestProperty("token","MYTOKEN");
con.setRequestMethod("GET");
int responseCode = con.getResponseCode(); 

注意:需确保connect()调用后请求尚未发送,部分场景下可能需要配合setDoOutput(true)调整调用顺序。

方案2:手动指定代理替代系统代理

不依赖系统代理的默认处理逻辑,手动设置代理信息:

// 手动指定代理地址和端口
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("proxy-host", 8080));
URL obj = new URL(URL);
HttpURLConnection con = (HttpURLConnection) obj.openConnection(proxy);
con.setRequestMethod("GET");
con.setRequestProperty("token","MYTOKEN");
// 若需自定义SSL信任,可在此补充相关配置
int responseCode = con.getResponseCode(); 

方案3:切换至成熟HTTP客户端库

如果HttpURLConnection的原生问题难以规避,建议切换至Apache HttpClient或OkHttp等第三方库,这类库对代理和请求头的处理更稳定:
OkHttp示例代码:

OkHttpClient client = new OkHttpClient.Builder()
    .proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("proxy-host", 8080)))
    .build();

Request request = new Request.Builder()
    .url(URL)
    .addHeader("token", "MYTOKEN")
    .build();

Response response = client.newCall(request).execute();

补充说明

该问题未被广泛关注的原因:多数场景下开发者使用的是标准认证头(如Authorization),这类头在隧道处理中有特殊保留逻辑;而自定义请求头的场景相对小众,且很多开发者会直接选择更易用的第三方HTTP客户端,因此问题曝光度较低。

内容的提问来源于stack exchange,提问作者El Turbo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 00:22:24