Как настроить прокси для использования JVM

Часто Java-приложение должно подключаться к Интернету. Наиболее распространенный пример происходит, когда он читает файл XML и ему необходимо загрузить свою схему.

Я за прокси-сервером. Как мне настроить мою JVM на использование прокси?

22 ответа

Решение

Из документации Java (не API Javadoc):

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

Установите флаги JVM http.proxyHost а также http.proxyPort при запуске вашей JVM в командной строке. Обычно это делается в сценарии оболочки (в Unix) или в файле bat (в Windows). Вот пример со сценарием оболочки Unix:

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.*.*.*|*.foo.com‌​|etc"

Чтобы использовать настройку прокси системы:

java -Djava.net.useSystemProxies=true ...

Или программно:

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

Источник: http://docs.oracle.com/javase/7/docs/api/java/net/doc-files/net-properties.html

Чтобы установить 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-прокси работают на разных уровнях сетевого стека, поэтому вы можете использовать один или другой, или оба.

Вы можете установить эти флаги программно следующим образом:

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

Просто верните правильные значения из методов needsProxy(), getProxyHost() а также getProxyPort() и вы можете называть этот фрагмент кода, когда захотите.

JVM использует прокси для выполнения HTTP-вызовов

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

Это может использовать настройки прокси пользователя

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

Установить java.net.useSystemProxies собственность на true, Вы можете установить его, например, через переменную среды JAVA_TOOL_OPTIONS. В Ubuntu вы можете, например, добавить следующую строку в .bashrc:

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

Сочетание ответов Сортера и Джавабретта / Леонеля:

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

Вы можете установить некоторые свойства прокси-сервера в качестве параметров jvm

-Dhttp.proxyPort=8080, proxyHost и т. Д.

но если вам нужно пройти через прокси-сервер аутентификации, вам нужен такой аутентификатор, как в следующем примере:

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

    }
}

На основании этого ответа: http://mail-archives.apache.org/mod_mbox/jakarta-jmeter-user/200208.mbox/%3C494FD350388AD511A9DD00025530F33102F1DC2C@MMSX006%3E

Ниже показано, как установить в Java прокси с прокси-пользователем и паролем прокси из командной строки, что является очень распространенным случаем. Не стоит сохранять пароли и хосты в коде, как правило, в первую очередь.

Передача системных свойств в командной строке с помощью -D и установка их в коде с помощью System.setProperty("имя", "значение") эквивалентны.

Но учтите это

Пример, который работает:

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.proxyHost, https.proxyPort и т. Д.

Если вы обращаетесь к службе HTTP, вы должны использовать http.proxyHost, http.proxyPort и т. Д.

Если вы хотите "Socks Proxy", сообщите аргументы VM "socksProxyHost" и "socksProxyPort".

например

java -DsocksProxyHost=127.0.0.1 -DsocksProxyPort=8080 org.example.Main

чтение файла XML и необходимо загрузить его схему

Если вы рассчитываете получить схемы или DTD через Интернет, вы создаете медленное, болтливое, хрупкое приложение. Что происходит, когда этот удаленный сервер, на котором размещается файл, берет запланированное или незапланированное время простоя? Ваше приложение ломается. Это нормально?

См. http://xml.apache.org/commons/components/resolver/resolver-article.html.

URL-адреса для схем и т.п. лучше всего рассматривать как уникальные идентификаторы. Не так, как запросы на удаленный доступ к этому файлу. Выполните поиск в Google по каталогу XML. Каталог XML позволяет размещать такие ресурсы локально, устраняя медлительность, болтливость и хрупкость.

Это в основном постоянно кэшированная копия удаленного контента. И это нормально, так как удаленный контент никогда не изменится. Если когда-нибудь будет обновление, оно будет по другому URL. Делать фактический поиск ресурса через интернет особенно глупо.

Я также за брандмауэром, это сработало для меня!

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();

Добавьте это, прежде чем подключаться к 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");

Это небольшое обновление, но начиная с 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

Недавно я обнаружил способ разрешить 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;
    }
}

После этого настройки прокси доступны для API Java через java.net.ProxySelector,

Единственная проблема с этим подходом состоит в том, что вам нужно запустить JVM с deploy.jar в bootclasspath, например java -Xbootclasspath/a:"%JAVA_HOME%\jre\lib\deploy.jar" -jar my.jar, Если кто-то знает, как преодолеть это ограничение, дайте мне знать.

Это подходит для меня:

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");
    }
}

P / S: Я основываюсь на ответе GHad.

Как указано в других ответах, если вам нужно использовать прокси-серверы с проверкой подлинности, нет надежного способа сделать это исключительно с помощью переменных командной строки - что раздражает, если вы используете чужое приложение и не хотите связываться с исходный код.

Will Iverson делает полезное предложение в разделе Использование HttpProxy для подключения к хосту с предварительной проверкой подлинности, чтобы использовать инструмент управления прокси, такой как Proxifier ( http://www.proxifier.com/ для Mac OS X и Windows), чтобы справиться с этим.

Например, с Proxifier вы можете настроить его на перехват только команд Java, которые будут управляться и перенаправляться через его (аутентифицированный) прокси. В этом случае вы захотите установить значения proxyHost и proxyPort пустыми, например, передать -Dhttp.proxyHost= -Dhttp.proxyPort= к вашим командам Java.

Это полный пример, который работал у меня — обратите внимание, что для HTTPS есть отдельные свойства (согласно https://docs.oracle.com/javase/8/docs/technotes/guides/net/proxys.html ).

Код ниже отправляет запрос к API https://api.myip.com и печатает ответ.

      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);
}

Кроме того, если вы всегда хотите загрузить одну и ту же схему, вы можете добавить схему в ваш путь к классам (файловую систему или JAR), а затем использовать пользовательский EntityResolver.

Смотрите здесь для более полного обсуждения этого подхода.

Изменить: см. @ Me.yahoo.com/a/0QMxE обсуждение CatalogResolver, который использует подход EntityResolver:

CatalogResolver cr = new CatalogResolver();
...
yourParser.setEntityResolver(cr) 

Я знаю, что вопрос явно касается функциональности внутри Java. Однако я думаю, что важно подумать о том, СЛЕДУЕТ ли вам настраивать прокси внутри вашего приложения. Я хочу ясно дать понять, что, с моей точки зрения, это не лучшая практика. По моему опыту, такой подход привел к сложной настройке и шаблонному коду.

Главным образом из-за лучшей переносимости и разделения задач вам следует попытаться решить эту проблему НЕ на уровне приложения. Кроме того, для разных частей вашего приложения могут потребоваться разные конфигурации прокси-сервера из-за несоответствий внутри ваших зависимостей.

Особенно если ваше приложение работает в контейнере, это усложнит вам жизнь. Основные контейнерные платформы имеют собственные решения для реализации настройки прокси-сервера с помощью сетевых политик, служб и настроек прокси-сервера на уровне платформы. Обработка сетевых настроек на уровне приложения будет мешать платформенным решениям.

Пожалуйста, рассмотрите возможность настройки вашей хостинговой системы для использования прокси, настройки сервера, на котором работает ваше приложение, или настройки контейнера, в котором работает ваше приложение.

Вы можете использовать переменные http.proxy* JVM, если вы находитесь в автономной JVM, но НЕ ДОЛЖНЫ изменять их сценарии запуска и / или делать это на сервере приложений (за исключением, возможно, jboss или tomcat). Вместо этого вы должны использовать JAVA Proxy API (не System.setProperty) или использовать собственные параметры конфигурации поставщика. Как в WebSphere, так и в WebLogic есть очень определенные способы настройки прокси, которые намного мощнее, чем J2SE. Кроме того, для WebSphere и WebLogic вы, скорее всего, нарушите работу своего сервера приложений, переопределив сценарии запуска (особенно процессы взаимодействия с сервером, поскольку вы, возможно, говорите им также использовать ваш прокси-сервер...).

Я думаю, что настройка WINHTTP также будет работать.

Многие программы, в том числе Windows Updates, имеют проблемы с прокси. При настройке WINHTTP всегда будут решаться проблемы такого рода.

Другие вопросы по тегам