Tomcat环境下HTTPS请求转代理:JVM参数可行还是需代码实现?
-Dhttps.proxyHost/-Dhttps.proxyPort with OkHttp3/Retrofit on Tomcat? Great question! Let's break this down based on your setup with OkHttp3, Retrofit, and Tomcat—since these libraries have specific behavior around proxy configuration that differs from standard JVM HTTP clients.
Short Answer
The -Dhttps.proxyHost and -Dhttps.proxyPort JVM parameters won't work out of the box for OkHttp/Retrofit requests. OkHttp doesn't automatically read system proxy settings by default. You'll need to explicitly configure OkHttpClient to use either the system proxy (leveraging those JVM params) or hardcode proxy details directly in your code.
Detailed Solutions
Here are two reliable approaches to get your HTTPS traffic routing through a proxy:
1. Use System Proxy Settings (Leverage -D Parameters)
If you want to keep proxy configuration flexible (no code changes when switching proxies), configure OkHttp to use the JVM's default proxy selector. This will pick up the -Dhttps.proxyHost and -Dhttps.proxyPort values you set for Tomcat.
First, update your OkHttpClient setup:
// Get the system's default proxy selector (reads JVM -D params) ProxySelector systemProxySelector = ProxySelector.getDefault(); OkHttpClient okHttpClient = new OkHttpClient.Builder() .proxySelector(systemProxySelector) // Add proxy authentication if your proxy requires it .proxyAuthenticator((route, response) -> { String proxyCredentials = Credentials.basic("proxy-username", "proxy-password"); return response.request().newBuilder() .header("Proxy-Authorization", proxyCredentials) .build(); }) .build(); // Attach this client to your Retrofit instance Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://target-api-domain.com/") .client(okHttpClient) .addConverterFactory(GsonConverterFactory.create()) .build();
Then, add the proxy params to your Tomcat startup script (e.g., catalina.sh for Linux/Mac or catalina.bat for Windows):
# Linux/Mac example (add to catalina.sh) export JAVA_OPTS="$JAVA_OPTS -Dhttps.proxyHost=your-proxy-host -Dhttps.proxyPort=your-proxy-port"
rem Windows example (add to catalina.bat) set JAVA_OPTS=%JAVA_OPTS% -Dhttps.proxyHost=your-proxy-host -Dhttps.proxyPort=your-proxy-port
2. Hardcode Proxy Details (For Fixed Proxies)
If you don't need to change proxies often, you can directly define the proxy in your OkHttpClient builder:
// Define your proxy directly Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("your-proxy-host", 8080)); OkHttpClient okHttpClient = new OkHttpClient.Builder() .proxy(proxy) // Add auth if needed .proxyAuthenticator((route, response) -> { String creds = Credentials.basic("proxy-user", "proxy-pass"); return response.request().newBuilder() .header("Proxy-Authorization", creds) .build(); }) .build(); // Attach to Retrofit as before Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://target-api-domain.com/") .client(okHttpClient) .build();
Key Notes
- SOCKS Proxies: If your proxy uses SOCKS instead of HTTP, change
Proxy.Type.HTTPtoProxy.Type.SOCKSin the code above. - Exclude Internal Domains: If you need some requests (e.g., internal APIs) to bypass the proxy, create a custom
ProxySelectorto skip proxying for specific domains:ProxySelector customSelector = new ProxySelector() { private final ProxySelector defaultSelector = ProxySelector.getDefault(); @Override public List<Proxy> select(URI uri) { // Skip proxy for internal domains if (uri.getHost().endsWith("your-internal-domain.com")) { return Collections.singletonList(Proxy.NO_PROXY); } return defaultSelector.select(uri); } @Override public void connectFailed(URI uri, SocketAddress sa, IOException ioe) { defaultSelector.connectFailed(uri, sa, ioe); } };
内容的提问来源于stack exchange,提问作者Michael Fletcher

