Java使用SOCKS代理而非HTTP代理时连接报错的解决咨询
问题描述
尝试通过代理连接服务器,设置代理的代码如下:
try { System.setProperty("java.net.useSystemProxies", "true"); System.out.println("detecting proxies"); List l = null; try { l = ProxySelector.getDefault().select(new URI("https://www.google.com")); } catch (URISyntaxException e) { e.printStackTrace(); System.out.println("Failed to list the proxy..." + e.getMessage()); } if (l != null) { for (Iterator iter = l.iterator(); iter.hasNext();) { java.net.Proxy proxy = (java.net.Proxy) iter.next(); System.out.println("proxy type: " + proxy.type()); InetSocketAddress addr = (InetSocketAddress) proxy.address(); if (addr == null) { System.out.println("No Proxy"); } else { System.out.println("proxy hostname: " + addr.getHostName()); System.setProperty("http.proxyHost", addr.getHostName()); System.setProperty("https.proxyHost", addr.getHostName()); System.out.println("proxy port: " + addr.getPort()); System.setProperty("http.proxyPort", Integer.toString(addr.getPort())); System.setProperty("https.proxyPort", Integer.toString(addr.getPort())); } } } } catch (Exception e) { e.printStackTrace(); }
发送请求的代码:
RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), jsonValue); Request request = new Request.Builder().url(settings.getServiceUrl() + "/" + service).addHeader("Authorization", Credentials.basic(settings.getServiceUserName(), settings.getServicePassword())).post(body).build(); OkHttpClient.Builder builder =new OkHttpClient.Builder(); OkHttpClient client = builder.readTimeout(6000 * 1000, TimeUnit.MILLISECONDS) .writeTimeout(6000 * 1000, TimeUnit.MILLISECONDS).build(); Call call = client.newCall(request); Response response = call.execute();
运行后抛出错误:
java.net.SocketException: Malformed reply from SOCKS server at java.net.SocksSocketImpl.readSocksReply(Unknown Source) at java.net.SocksSocketImpl.connect(Unknown Source) at java.net.Socket.connect(Unknown Source) at okhttp3.internal.platform.Platform.connectSocket(Platform.java:130) at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.java:263) at okhttp3.internal.connection.RealConnection.connectTunnel(RealConnection.java:235) at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:177) at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.java:224)
解决方法
该错误的核心原因是用HTTP代理的配置逻辑处理SOCKS代理,两种代理协议不兼容导致握手失败。以下是针对性解决步骤:
1. 区分代理类型适配配置
ProxySelector可能返回SOCKS类型代理,但你当前代码统一按HTTP/HTTPS代理设置系统属性,需修改逻辑区分处理:
try { System.setProperty("java.net.useSystemProxies", "true"); System.out.println("detecting proxies"); List<Proxy> proxyList = ProxySelector.getDefault().select(new URI(settings.getServiceUrl() + "/" + service)); if (proxyList != null) { for (Proxy proxy : proxyList) { System.out.println("proxy type: " + proxy.type()); InetSocketAddress addr = (InetSocketAddress) proxy.address(); if (addr == null) { System.out.println("No Proxy"); continue; } String host = addr.getHostName(); int port = addr.getPort(); if (proxy.type() == Proxy.Type.HTTP) { // HTTP/HTTPS代理设置对应系统属性 System.setProperty("http.proxyHost", host); System.setProperty("https.proxyHost", host); System.setProperty("http.proxyPort", String.valueOf(port)); System.setProperty("https.proxyPort", String.valueOf(port)); } else if (proxy.type() == Proxy.Type.SOCKS) { // SOCKS代理需单独设置专用属性 System.setProperty("socksProxyHost", host); System.setProperty("socksProxyPort", String.valueOf(port)); // 若SOCKS代理需要认证,补充以下配置: // System.setProperty("java.net.socks.username", "your-socks-username"); // System.setProperty("java.net.socks.password", "your-socks-password"); } } } } catch (Exception e) { e.printStackTrace(); }
2. 直接给OkHttpClient配置代理(推荐)
系统属性是全局生效,不如直接在OkHttpClient中配置对应代理,更灵活且避免冲突:
RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), jsonValue); Request request = new Request.Builder() .url(settings.getServiceUrl() + "/" + service) .addHeader("Authorization", Credentials.basic(settings.getServiceUserName(), settings.getServicePassword())) .post(body) .build(); OkHttpClient.Builder builder = new OkHttpClient.Builder(); // 获取适配目标URL的代理列表 List<Proxy> proxyList = ProxySelector.getDefault().select(new URI(settings.getServiceUrl() + "/" + service)); if (!proxyList.isEmpty()) { Proxy proxy = proxyList.get(0); // 取第一个可用代理,可根据实际调整选择逻辑 builder.proxy(proxy); // 若为需要认证的SOCKS代理,添加认证器 if (proxy.type() == Proxy.Type.SOCKS) { builder.proxyAuthenticator(new Authenticator() { @Override public Request authenticate(Route route, Response response) throws IOException { String credential = Credentials.basic("socks-username", "socks-password"); return response.request().newBuilder() .header("Proxy-Authorization", credential) .build(); } }); } } OkHttpClient client = builder .readTimeout(6000 * 1000, TimeUnit.MILLISECONDS) .writeTimeout(6000 * 1000, TimeUnit.MILLISECONDS) .build(); Call call = client.newCall(request); Response response = call.execute();
3. 排查代理服务本身问题
- 确认SOCKS代理服务器地址、端口正确,服务处于运行状态
- 用工具测试代理可用性,比如执行
curl -x socks5://proxy-host:port your-service-url验证是否能正常访问目标服务
内容的提问来源于stack exchange,提问作者kiran
相关产品推荐
相关产品推荐

