如何设置JVM使用的代理

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

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

401

根据Java文档(不是javadoc API):

http://download.oracle.com/javase/6/docs/technotes/guides/net/proxies.html

在命令行中启动JVM时,设置http.proxyHosthttp.proxyPort JVM标志。 这通常在shell脚本(Unix)或bat文件(Windows)中完成。以下是Unix shell脚本的示例:

JAVA_FLAGS=-Dhttp.proxyHost=10.0.0.100 -Dhttp.proxyPort=8800
java ${JAVA_FLAGS} ...

当使用像JBoss或WebLogic这样的容器时,我的解决方案是编辑供应商提供的启动脚本。

许多开发人员熟悉Java API(javadocs),但往往忽视了其余文档。它包含许多有趣的信息:http://download.oracle.com/javase/6/docs/technotes/guides/


更新:如果您不想使用代理解析某些本地/内部主机,请查看@Tomalak的评论:

还要记得http.nonProxyHosts属性!

-Dhttp.nonProxyHosts="localhost|127.0.0.1|10.*.*.*|*.example.com|etc"

6
大家好,你们如何在这里同时包含用户名和密码?谢谢。 - Joeblackdev
8
请查看 http.proxyUser 和 http.proxyPassword。 - aasukisuki
1
根据我的经验:要查找代理地址,请转到IE->InternetOptions->Lan设置。 - Srujan Kumar Gulla
5
@aasukisuki http.proxyUserhttp.proxyPassword 不是 Java 系统属性,它们是用于 Apache HTTP 客户端的。 - user207421
41
同时,不要忘记为HTTPS配置https.proxyHosthttps.proxyPort - C-Otto
显示剩余6条评论

143

很棒的设置JVM参数对我非常有效..谢谢 - nanosoft
我使用了这段代码,在我的SSLSocket上通过“false”值来禁用代理。谢谢。 - Fer
1
也许是因为我的代理需要身份验证,所以这对我没有起作用。但我希望它能够工作。 - Simon Forsberg
5
这无法与代理自动配置(PAC)文件一起使用,请参见https://dev59.com/7Wkv5IYBdhLWcg3w1kEJ。 - Michael_S
尽管在VM参数中显示,但这并没有起作用。任何帮助将不胜感激。 - Anurag
已经过去了10年,但我认为这只是获取代理服务器IP(或DNS)和端口。我不认为Java知道如何获取身份验证信息。也许是因为有几十种完全不相关的身份验证方法之类的东西。我还不得不添加大量代码来询问用户并存储和传输用户名/密码,即使那也不够好,因为还有其他类型的身份验证。 - gr5

92

编程设置HTTP/HTTPS和/或SOCKS代理:

...

public void setProxy() {
    if (isUseHTTPProxy()) {
        // HTTP/HTTPS Proxy
        System.setProperty("http.proxyHost", getHTTPHost());
        System.setProperty("http.proxyPort", getHTTPPort());
        System.setProperty("https.proxyHost", getHTTPHost());
        System.setProperty("https.proxyPort", getHTTPPort());
        if (isUseHTTPAuth()) {
            String encoded = new String(Base64.encodeBase64((getHTTPUsername() + ":" + getHTTPPassword()).getBytes()));
            con.setRequestProperty("Proxy-Authorization", "Basic " + encoded);
            Authenticator.setDefault(new ProxyAuth(getHTTPUsername(), getHTTPPassword()));
        }
    }
    if (isUseSOCKSProxy()) {
        // SOCKS Proxy
        System.setProperty("socksProxyHost", getSOCKSHost());
        System.setProperty("socksProxyPort", getSOCKSPort());
        if (isUseSOCKSAuth()) {
            System.setProperty("java.net.socks.username", getSOCKSUsername());
            System.setProperty("java.net.socks.password", getSOCKSPassword());
            Authenticator.setDefault(new ProxyAuth(getSOCKSUsername(), getSOCKSPassword()));
        }
    }
}

...

public class ProxyAuth extends Authenticator {
    private PasswordAuthentication auth;

    private ProxyAuth(String user, String password) {
        auth = new PasswordAuthentication(user, password == null ? new char[]{} : password.toCharArray());
    }

    protected PasswordAuthentication getPasswordAuthentication() {
        return auth;
    }
}

...

请记住,HTTP代理和SOCKS代理在网络堆栈中的不同层级上运行,因此您可以使用其中一个或两者兼用。


4
如果已经设置了“java.net.socks.username/password”,为什么还要设置Authenticator? - user207421
3
为什么 "con.setRequest..." 中的 con 无法识别?需要哪些库才能实现这个功能。 - Randnum
1
有时候 HTTP 代理无法解决我的问题,所以为袜子代理选项点赞。 - manuzhang
1
在我的测试中,如果您仅设置默认的身份验证器,则可以正常工作,无需设置身份验证属性。 - Drew Stephens
1
如果只使用系统属性,它将无法工作。我认为java.net.socks.(username|password)属性没有任何作用。 - Drew Stephens
显示剩余2条评论

50

您可以通过编程的方式设置这些标志:

if (needsProxy()) {
    System.setProperty("http.proxyHost",getProxyHost());
    System.setProperty("http.proxyPort",getProxyPort());
} else {
    System.setProperty("http.proxyHost","");
    System.setProperty("http.proxyPort","");
}

只需从needsProxy()getProxyHost()getProxyPort()方法中返回正确的值,您就可以在任何时候调用此代码片段。


36
"proxySet" 无效。证明:将其设置为“false”。尽管各种书籍和在线参考资料都声称有这个属性,但实际上在JDK中从未存在过这样的属性。它来自于已经消亡的HotJavaBean,它是一个封装的浏览器,在1998年左右消失了。 - user207421
3
产权名称是否不包含 http/https? - Betlista
18
这里有三个错误:1. 如前所述,没有"proxySet"项;2. "proxyHost" 和 "proxyPort" 应该为 "http.proxyHost" 和 "http.proxyPort" (或对应的 'https');3. System.getProperties().put(X,Y) 不等于 System.setProperty(X,Y)。除此之外,答案非常好。 - Rob Cranfill
几乎正确。请参见:http://memorynotfound.com/configure-http-proxy-settings-java/ - csvan
1
@RobCranfill 1:“proxySet”曾经是一个非标准标志,旧版JDK需要它,但现在不再需要;2:“proxyHost”和“proxyPort”确实有效,“http.”前缀只是将它们限制在HTTP协议中(类似于“https.”);3:在这一点上你是正确的。 - toolforger

26

JVM使用代理进行HTTP调用。

System.getProperties().put("http.proxyHost", "someProxyURL");
System.getProperties().put("http.proxyPort", "someProxyPort");

这可能会使用用户设置的代理

System.setProperty("java.net.useSystemProxies", "true");

2
使用System.setProperty代替System.getProperties().put(...) - Simon Forsberg

18

java.net.useSystemProxies 属性设置为 true。例如,您可以通过 JAVA_TOOL_OPTIONS 环境变量来设置它。在Ubuntu中,您可以将以下行添加到 .bashrc 文件中:

export JAVA_TOOL_OPTIONS+=" -Djava.net.useSystemProxies=true"


这个选项在 Docker 内部不起作用,只有像这样添加 ARG _JAVA_OPTIONS="-Dhttps.proxyHost=myproxy -Dhttps.proxyPort=myport" 才能生效。但硬编码并不可行。 - user3999721

18

将Sorter和javabrett/Leonel的答案结合起来:

java -Dhttp.proxyHost=10.10.10.10 -Dhttp.proxyPort=8080 -Dhttp.proxyUser=username -Dhttp.proxyPassword=password -jar myJar.jar

13

你可以将一些代理服务器的属性设置为jvm参数

-Dhttp.proxyPort=8080, proxyHost等等。

但是,如果您需要通过身份验证代理,您需要像这个示例中的Authenticator:

ProxyAuthenticator.java

import java.net.*;
import java.io.*;

public class ProxyAuthenticator extends Authenticator {

    private String userName, password;

    protected PasswordAuthentication getPasswordAuthentication() {
        return new PasswordAuthentication(userName, password.toCharArray());
    }

    public ProxyAuthenticator(String userName, String password) {
        this.userName = userName;
        this.password = password;
    }
}

Example.java

    import java.net.Authenticator;
    import ProxyAuthenticator;

public class Example {

    public static void main(String[] args) {
        String username = System.getProperty("proxy.authentication.username");
        String password = System.getProperty("proxy.authentication.password");

                if (username != null && !username.equals("")) {
            Authenticator.setDefault(new ProxyAuthenticator(username, password));
        }

                // here your JVM will be authenticated

    }
}
Based on this reply: http://mail-archives.apache.org/mod_mbox/jakarta-jmeter-user/200208.mbox/%3C494FD350388AD511A9DD00025530F33102F1DC2C@MMSX006%3E

这个不起作用。如果您尚未进行身份验证,则主函数中的第一行会获取一堆空值,代码将停止。这并不能帮助某人验证他们的jvm,以便他们可以通过代理进行URL调用。 - Randnum

12
以下内容展示了如何在Java中从命令行设置带有代理用户和代理密码的代理,这是一个非常常见的情况。通常不应该在代码中保存密码和主机名。通过使用-D在命令行中传递系统属性并使用System.setProperty("name", "value")在代码中设置它们是等效的。但请注意:下面的例子有效:
C:\temp>java -Dhttps.proxyHost=host -Dhttps.proxyPort=port -Dhttps.proxyUser=user -Dhttps.proxyPassword="password" -Djavax.net.ssl.trustStore=c:/cacerts -Djavax.net.ssl.trustStorePassword=changeit com.andreas.JavaNetHttpConnection

但是以下无法工作

C:\temp>java com.andreas.JavaNetHttpConnection -Dhttps.proxyHost=host -Dhttps.proxyPort=port -Dhttps=proxyUser=user -Dhttps.proxyPassword="password" -Djavax.net.ssl.trustStore=c:/cacerts -Djavax.net.ssl.trustStorePassword=changeit
唯一的区别是系统属性的位置!(在类之前和之后)。
如果您的密码中有特殊字符,可以像上面的示例一样将其用引号"@MyPass123%"括起来。
如果要访问HTTPS服务,则必须使用https.proxyHosthttps.proxyPort等。
如果要访问HTTP服务,则必须使用http.proxyHosthttp.proxyPort等。

6
ProxyUser和proxyPassword不是Java系统属性,而是Apache HTTP客户端属性,因此这并非在所有情况下都适用。 - THelper

9
如果您想使用“Socks代理”,请设置“socksProxyHost”和“socksProxyPort”虚拟机参数。
例如:
java -DsocksProxyHost=127.0.0.1 -DsocksProxyPort=8080 org.example.Main

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