如何设置JVM使用的代理

368
很多时候,Java 应用程序需要连接到互联网。最常见的例子是在读取 XML 文件并需要下载其模式时。
我使用代理服务器。如何设置我的 JVM 使用代理?

这方面的Oracle文档似乎相当陈旧(尽管仍然可能有效)。这里有一些来自Spring更现代的东西:https://docs.spring.io/spring-integration/reference/html/http.html#http-proxy - Brent Bradburn
21个回答

8
读取XML文件并需要下载其模式。
如果您希望通过互联网检索模式或DTD,那么您正在构建一个缓慢、冗长和易破坏的应用程序。当托管文件的远程服务器计划或意外中断时会发生什么?您的应用程序会出现故障,这样可以吗?
请参见http://xml.apache.org/commons/components/resolver/resolver-article.html#s.catalog.files 最好将架构等URL视为唯一标识符。而非实际远程访问该文件的请求。在Google上搜索“XML catalog”。XML目录允许您在本地托管此类资源,解决了缓慢、冗长和易破坏的问题。
它基本上是远程内容的永久缓存副本。这没问题,因为远程内容永远不会更改。如果有更新,它将位于不同的URL。因此,通过互联网实际检索资源特别愚蠢。

7
我也在防火墙后面,这对我起了作用!
System.setProperty("http.proxyHost", "proxy host addr");
System.setProperty("http.proxyPort", "808");
Authenticator.setDefault(new Authenticator() {
    protected PasswordAuthentication getPasswordAuthentication() {

        return new PasswordAuthentication("domain\\user","password".toCharArray());
    }
});

URL url = new URL("http://www.google.com/");
URLConnection con = url.openConnection();

BufferedReader in = new BufferedReader(new InputStreamReader(
                    con.getInputStream()));

// Read it ...
String inputLine;
while ((inputLine = in.readLine()) != null)
    System.out.println(inputLine);

in.close();

4
这是一个小更新,但自Java 7以来,代理连接现在可以通过编程方式创建,而不是通过系统属性。这可能在以下情况下很有用:
  1. 需要在程序运行时动态旋转代理
  2. 需要使用多个并行代理
  3. 或只是使代码更清晰 :)
以下是 groovy 中的一个人为例子:
// proxy configuration read from file resource under "proxyFileName"
String proxyFileName = "proxy.txt"
String proxyPort = "1234"
String url = "http://www.promised.land"
File testProxyFile = new File(proxyFileName)
URLConnection connection

if (!testProxyFile.exists()) {

    logger.debug "proxyFileName doesn't exist.  Bypassing connection via proxy."
    connection = url.toURL().openConnection()

} else {
    String proxyAddress = testProxyFile.text
    connection = url.toURL().openConnection(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyAddress, proxyPort)))
}

try {
    connection.connect()
}
catch (Exception e) {
    logger.error e.printStackTrace()
}

完整参考文档:http://docs.oracle.com/javase/7/docs/technotes/guides/net/proxies.html

本文档介绍了Java中与代理服务器有关的内容,包括如何设置和使用代理服务器。如果您需要在网络通信过程中使用代理服务器,可以参考这份文档来了解相关知识。


2
这是自Java 1.5开始的,不是1.7。 - user207421

4
在连接代理后的 URL 之前添加此代码。
System.getProperties().put("http.proxyHost", "someProxyURL");
System.getProperties().put("http.proxyPort", "someProxyPort");
System.getProperties().put("http.proxyUser", "someUserName");
System.getProperties().put("http.proxyPassword", "somePassword");

5
http.proxyUserhttp.proxyPassword 不是Java系统属性,它们是用于Apache HTTP客户端的。 - user207421
1
使用 System.setProperty 替代 System.getProperties().put(...) - Simon Forsberg

3

最近我发现了一种让JVM使用浏览器代理设置的方法。你需要做的是将${java.home}/lib/deploy.jar添加到你的项目中,并像下面这样初始化库:

import com.sun.deploy.net.proxy.DeployProxySelector;
import com.sun.deploy.services.PlatformType;
import com.sun.deploy.services.ServiceManager;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public abstract class ExtendedProxyManager {

    private static final Log logger = LogFactory.getLog(ExtendedProxyManager.class);

    /**
     * After calling this method, proxy settings can be magically retrieved from default browser settings.
     */
    public static boolean init() {
        logger.debug("Init started");

        // Initialization code was taken from com.sun.deploy.ClientContainer:
        ServiceManager
                .setService(System.getProperty("os.name").toLowerCase().indexOf("windows") != -1 ? PlatformType.STANDALONE_TIGER_WIN32
                        : PlatformType.STANDALONE_TIGER_UNIX);

        try {
            // This will call ProxySelector.setDefault():
            DeployProxySelector.reset();
        } catch (Throwable throwable) {
            logger.error("Unable to initialize extended dynamic browser proxy settings support.", throwable);

            return false;
        }

        return true;
    }
}

接下来,代理设置可通过 java.net.ProxySelector 在 Java API 中使用。

这种方法的唯一问题是你需要在启动 JVM 时使用 deploy.jar 在 bootclasspath 中,例如 java -Xbootclasspath/a:"%JAVA_HOME%\jre\lib\deploy.jar" -jar my.jar。如果有人知道如何克服这个限制,请告诉我。


1
我希望我能多次点赞,这是唯一对我有效的解决方案;谢谢!我不得不从这里下载apache commons logging jar:https://commons.apache.org/proper/commons-logging/download_logging.cgi 我的Main()代码: System.setProperty("java.net.useSystemProxies", "true"); System.out.println("detecting proxies"); ExtendedProxyManager.init(); - Boris
xbootclasspath指向deploy.jar会产生什么影响,如果我在没有WebStart的情况下将该jar文件放到普通类路径上,会发生什么? - Houtman
1
在JDK 9中,它失败了 :( Exception in thread "main" java.lang.IllegalAccessError: class ...) cannot access class com.sun.deploy.net.proxy.DeployProxySelector (in module jdk.deploy) because module jdk.deploy does not export com.sun.deploy.net.proxy - Houtman

3
这对我来说没问题:
public void setHttpProxy(boolean isNeedProxy) {
    if (isNeedProxy) {
        System.setProperty("http.proxyHost", getProxyHost());
        System.setProperty("http.proxyPort", getProxyPort());
    } else {
        System.clearProperty("http.proxyHost");
        System.clearProperty("http.proxyPort");
    }
}

附注:我基于GHad的答案。


这个答案没有提供任何其他答案中没有说过的内容。 - Simon Forsberg

1

正如其他答案所指出的那样,如果您需要使用身份验证代理,则没有可靠的方法仅使用命令行变量来实现这一点 - 如果您正在使用别人的应用程序并且不想干扰源代码,则这很烦人。

Will Iverson使用HttpProxy连接到具有预先认证的主机上提出了有用的建议,建议使用代理管理工具,例如Proxifier( http://www.proxifier.com/适用于Mac OS X和Windows)来处理此问题。

例如,使用Proxifier,您可以设置它仅拦截要通过其(经过身份验证的)代理进行管理和重定向的Java命令。在这种情况下,您将希望将proxyHost和proxyPort值设置为空白,例如,将-Dhttp.proxyHost= -Dhttp.proxyPort=传递给您的Java命令。


1
这是我亲自测试过的完整示例-请注意,对于HTTPS,有单独的属性(请参阅https://docs.oracle.com/javase/8/docs/technotes/guides/net/proxies.html)。
下面的代码向https://api.myip.com API发送请求并打印响应。
public static void main(String[] args) throws IOException {
    System.setProperty("java.net.useSystemProxies", "true");
    final String proxyUser = "proxy-user";
    final String proxyPass = "password123";
    final String host = "some.proxy.io";
    final Integer port = 50201;

    // http
    System.setProperty("http.proxyHost",host);
    System.setProperty("http.proxyPort", String.valueOf(port));
    System.setProperty("http.proxyUser", proxyUser);
    System.setProperty("http.proxyPassword", proxyPass);

    // https
    System.setProperty("https.proxyHost",host);
    System.setProperty("https.proxyPort", String.valueOf(port));
    System.setProperty("https.proxyUser", proxyUser);
    System.setProperty("https.proxyPassword", proxyPass);

    System.setProperty("jdk.http.auth.tunneling.disabledSchemes", "");
    System.setProperty("jdk.https.auth.tunneling.disabledSchemes", "");

    Authenticator.setDefault(new Authenticator() {
                @Override
                public PasswordAuthentication getPasswordAuthentication() {
                    return new PasswordAuthentication(proxyUser, proxyPass.toCharArray());
                }
        }
    );

    // create and send a https request to myip.com API
    URL url = new URL("https://api.myip.com");
    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
    connection.setRequestMethod("GET");
    int status = connection.getResponseCode();
    
    // read the response
    BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
    String responseLine;
    StringBuffer responseContent = new StringBuffer();
    while ((responseLine = in.readLine()) != null) 
        responseContent.append(responseLine);
    
    in.close();
    connection.disconnect();
    
    // print the response
    System.out.println(status);
    System.out.println(responseContent);
}

0
我知道问题明确要求在Java内部进行功能配置。然而,我认为重要的是思考是否应该在应用程序内部配置代理。我想要非常清楚地表明,在我看来,这不是最佳实践。根据我的经验,这种方法会导致复杂的设置和样板代码。
主要是由于更好的可移植性和关注点分离,你应该尝试在应用程序层面之外解决这个问题。此外,你的应用程序的不同部分可能需要不同的代理配置,因为依赖项内部存在不一致性。
特别是如果你的应用程序运行在容器中,那么会让你的生活变得非常困难。主要的容器平台都有自己的解决方案来通过网络策略、服务和平台级别的代理设置来实现代理配置。在应用程序层面处理网络设置将干扰平台解决方案。
请考虑配置你的托管系统使用代理,配置你的应用程序所在的服务器,或者配置你的应用程序所在的容器。

-1
如果您在独立的JVM中,可以利用http.proxy* JVM变量,但不应修改它们的启动脚本并/或在应用服务器中执行此操作(除了jboss或tomcat之外)。而应使用JAVA代理API(而非System.setProperty)或利用供应商自己的配置选项。WebSphere和WebLogic都有非常明确定义的设置代理的方式,比J2SE更强大。此外,对于WebSphere和WebLogic,通过覆盖启动脚本(特别是服务器的交互过程),很可能会以微小的方式破坏应用程序服务器。

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