将JVM/JRE设置为自动使用Windows代理

39

我看到有关为JVM设置代理的问题,但我想问的是如何利用已经配置好的代理(在Windows上)。

这里是我的问题演示:

  1. 转到控制面板-> Java并设置代理地址。
  2. 运行以下简单的小程序代码(我正在使用Eclipse IDE):
import java.awt.Graphics;
import javax.swing.JApplet;
import java.util.*;

public class Stacklet extends JApplet {
    private String message;
    public void init(){
        Properties props = System.getProperties();
        message = props.getProperty("http.proxyHost", "NONE");      
        message = (message.length() == 0)? "NONE": message;
    }

    public void paint(Graphics g)
    {
        g.drawString(message, 20, 20);
    }
}

无论您在 Java 控制面板中设置了什么,该小程序都显示“NONE”。最好的解决方案是使用 Windows 代理设置(通常在 Internet Explorer 中设置),但在 Java 控制面板中执行额外的配置步骤仍然是可接受的解决方案。

谢谢!

6个回答

39

可以使用ProxySelector类检测代理,并通过将环境变量赋值给System类的setProperty方法分配系统代理:

System.setProperty("java.net.useSystemProxies", "true");
System.out.println("detecting proxies");
List l = null;
try {
    l = ProxySelector.getDefault().select(new URI("http://foo/bar"));
} 
catch (URISyntaxException e) {
    e.printStackTrace();
}
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.out.println("proxy port: " + addr.getPort());
            System.setProperty("http.proxyPort", Integer.toString(addr.getPort()));
        }
    }
}

6
我这里有代理,但是这段代码输出的是“检测到代理 代理主机名:DIRECT 没有代理”,但实际上连接到指定的URI超时失败了。 - Nikolay Kuznetsov
代理主机名:DIRECT 无代理。这是否意味着我没有使用代理? - Koray Tugay
3
相同的情况,我在代理后面,但使用此代码我会得到直接无代理。 - splinter123
1
java.net.useSystemProxies并不总是有效。我不知道它完全无法起作用的所有情况,但如果代理是透明的,即应用程序只进行直接连接,并且代理将拦截该连接而不通知它们时,它肯定不会起作用。 - toolforger

23

3
谢谢您的评论并提到此属性仅在启动时检查一次,这是该问题中没有提到的地方。 - fragorl
实际上,如果指定了此属性,则系统代理会自动使用! - MauganRa
3
这不适用于代理自动配置(PAC)文件,请参见https://dev59.com/7Wkv5IYBdhLWcg3w1kEJ - Michael_S
这个可以帮助绕过-javaagent的一些副作用(例如在Intellij IDEA中运行应用程序)。 - loic
1
这在使用Java 9及以上版本时可以与PAC文件一起使用 - 参见https://dev59.com/7Wkv5IYBdhLWcg3w1kEJ#57891805。 - Joman68

11
我在尝试这里建议的代码时发现了一种奇怪的行为。
似乎,在设置了默认的ProxySelector之后,常规的socket代码(例如创建一个新的Socket)就无法正常工作了,因为它会尝试使用socks服务器(我不确定为什么会这样,但对我来说确实是这样)。
因此,如果你在调用...
Socket socket = new Socket(host, port);

如果你收到了SocketException:

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 java.net.Socket.connect(Unknown Source)
    at java.net.Socket.<init>(Unknown Source)
    at java.net.Socket.<init>(Unknown Source)

然后尝试将默认的ProxySelector设置回null:

ProxySelector.setDefault(null);

对我而言,这导致了以下小的Java类,我现在使用它来简单地检索系统代理设置,而不影响应用程序中Sockets()的进一步使用,同时正确配置系统以使用代理:

public class ProxyConfig {

  private static String host;
  private static int port;

  public static void init() {
    System.setProperty("java.net.useSystemProxies", "true");
    Proxy proxy = getProxy();
    if (proxy != null) {
      InetSocketAddress addr = (InetSocketAddress) proxy.address();
      host = addr.getHostName();
      port = addr.getPort();

      System.setProperty("java.net.useSystemProxies", "false");
      System.setProperty("http.proxyHost", host);
      System.setProperty("http.proxyPort", ""+port);

    }
    System.setProperty("java.net.useSystemProxies", "false");
  }

  public static String getHost() {
    return host;
  }

  public static int getPort() {
    return port;
  }

  private static Proxy getProxy() {
    List<Proxy> l = null;
    try {
      ProxySelector def = ProxySelector.getDefault();

      l = def.select(new URI("http://foo/bar"));
      ProxySelector.setDefault(null);
    } catch (Exception e) {
      e.printStackTrace();
    }
    if (l != null) {
      for (Iterator<Proxy> iter = l.iterator(); iter.hasNext();) {
        java.net.Proxy proxy = iter.next();
        return proxy;
      }
    }
    return null;
  }
}

3

java.net.URL.openStream()java.net.URL.openConnection().getInputStream() 的简写形式。


2

更新:要想使以下解决方案生效,您需要设置系统属性java.net.useSystemProxiestrue

如果使用java.net.URL.openStream()获取网络资源内容的InputStream,则自动获取与Internet Explorer使用相同的代理。

无需进入Java控制面板或显示所使用的代理。


2
不对 - 这不是真的。或者如果它应该那样工作,它也不起作用。 - mmo
@mmo 您是正确的。感谢您指出这一点。我使用了java.net.useSystemProxies,但忘记提到它。这是一个重要的要点。 - Alain O'Dea
@mmo,我是否已经充分解决了您的问题,以便您撤销负评? - Alain O'Dea

2
try{
    System.setProperty("java.net.useSystemProxies", "true");
    String prx = ProxySelector.getDefault().select(new URI("http://www.google.com")).get(0).address().toString();
    JOptionPane.showMessageDialog(null, prx);
} catch(Exception e){
    JOptionPane.showMessageDialog(null, "no proxy");
}

2
你好,欢迎来到SO。你的回答只包含代码,如果你能加上一些评论来解释它的作用和如何使用会更好。你能否请编辑你的回答并添加它?谢谢! - Fabio says Reinstate Monica

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接