如何在不设置系统范围属性的情况下将HTTP代理用于JAX-WS请求?

时间:2022-06-06 20:15:05

I have an application that needs to make a SOAP client request to a system on the Internet, so it needs to go though our HTTP proxy.

我有一个应用程序需要向Internet上的系统发出SOAP客户端请求,因此需要通过我们的HTTP代理。

One can do this by setting system-wide values such as system properties:

可以通过设置系统范围的值(例如系统属性)来执行此操作:

// Cowboy-style.  Blow away anything any other part of the application has set.
System.getProperties().put("proxySet", "true");
System.getProperties().put("https.proxyHost", HTTPS_PROXY_HOST);  
System.getProperties().put("https.proxyPort", HTTPS_PROXY_PORT);

Or by setting the default ProxySelector (also a system-wide setting):

或者通过设置默认的ProxySelector(也是系统范围的设置):

// More Cowboy-style!  Every thing Google has found says to do it this way!?!?!
ProxySelector.setDefault(new MyProxySelector(HTTPS_PROXY_HOST, HTTPS_PROXY_PORT));

Neither of these is a wise choice if there is the possibility of other subsystems wanting to access web servers via different HTTP proxies or without any proxy. Using the ProxySelector would let me configure which connections use the proxy, but I would have to figure that out for every single thing in the huge application.

如果其他子系统可能希望通过不同的HTTP代理或没有任何代理访问Web服务器,这些都不是明智的选择。使用ProxySelector可以让我配置哪些连接使用代理,但是我必须为巨大的应用程序中的每一件事情弄清楚。

A reasonable API would have a method that took a java.net.Proxy object just like the java.net.Socket(java.net.Proxy proxy) constructor does. That way the necessary settings are local to the part of the system that needs to set them. Is there some way to do this with a JAX-WS?

合理的API会有一个方法,它接受一个java.net.Proxy对象,就像java.net.Socket(java.net.Proxy代理)构造函数一样。这样,必要的设置对于需要设置它们的系统部分是本地的。有没有办法用JAX-WS做到这一点?

I do not want to set a system-wide proxy configuration.

我不想设置系统范围的代理配置。

2 个解决方案

#1


5  

If you are using JAX-WS you might be able to set the socket factory used by the underlying HttpURLConnection. I see vague signs that this is possible for SSL (see HTTPS SSLSocketFactory) but I'm not certain if you can do that for regular HTTP connections (or quite frankly how that even works: the JAXWSProperties class they reference appears to be a non-standard JDK class).

如果您使用的是JAX-WS,则可以设置底层HttpURLConnection使用的套接字工厂。我看到一些模糊的迹象表明这可能是SSL(参见HTTPS SSLSocketFactory),但我不确定你是否可以为常规HTTP连接做到这一点(或者坦率地说它是如何工作的:它们引用的JAXWSProperties类似乎是非标准JDK类)。

If you can set the socket factory then you can configure a custom socket factory that uses the specific proxy you want.

如果可以设置套接字工厂,则可以配置使用所需特定代理的自定义套接字工厂。

#2


9  

I recommend using a custom ProxySelector. I had the same problem and it works great and is super flexible. It's simple too.

我建议使用自定义ProxySelector。我有同样的问题,它很有效,而且非常灵活。这也很简单。

Here's my CustomProxySelector:

这是我的CustomProxySelector:

import org.hibernate.validator.util.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.*;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

/**
 * So the way a ProxySelector works is that for all Connections made,
 * it delegates to a proxySelector(There is a default we're going to
 * override with this class) to know if it needs to use a proxy
 * for the connection.
 * <p>This class was specifically created with the intent to proxy connections
 * going to the allegiance soap service.</p>
 *
 * @author Nate
 */
class CustomProxySelector extends ProxySelector {

private final ProxySelector def;

private Proxy proxy;

private static final Logger logger = Logger.getLogger(CustomProxySelector.class.getName());

private List<Proxy> proxyList = new ArrayList<Proxy>();

/*
 * We want to hang onto the default and delegate
 * everything to it unless it's one of the url's
 * we need proxied.
 */
CustomProxySelector(String proxyHost, String proxyPort) {
    this.def = ProxySelector.getDefault();
    proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, (null == proxyPort) ? 80 : Integer.valueOf(proxyPort)));
    proxyList.add(proxy);
    ProxySelector.setDefault(this);
}

@Override
public List<Proxy> select(URI uri) {
    logger.info("Trying to reach URL : " + uri);
    if (uri == null) {
        throw new IllegalArgumentException("URI can't be null.");
    }
    if (uri.getHost().contains("allegiancetech")) {
        logger.info("We're trying to reach allegiance so we're going to use the extProxy.");
        return proxyList;
    }
    return def.select(uri);
}

/*
* Method called by the handlers when it failed to connect
* to one of the proxies returned by select().
*/
@Override
public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
    logger.severe("Failed to connect to a proxy when connecting to " + uri.getHost());
    if (uri == null || sa == null || ioe == null) {
        throw new IllegalArgumentException("Arguments can't be null.");
    }
    def.connectFailed(uri, sa, ioe);
}

}

#1


5  

If you are using JAX-WS you might be able to set the socket factory used by the underlying HttpURLConnection. I see vague signs that this is possible for SSL (see HTTPS SSLSocketFactory) but I'm not certain if you can do that for regular HTTP connections (or quite frankly how that even works: the JAXWSProperties class they reference appears to be a non-standard JDK class).

如果您使用的是JAX-WS,则可以设置底层HttpURLConnection使用的套接字工厂。我看到一些模糊的迹象表明这可能是SSL(参见HTTPS SSLSocketFactory),但我不确定你是否可以为常规HTTP连接做到这一点(或者坦率地说它是如何工作的:它们引用的JAXWSProperties类似乎是非标准JDK类)。

If you can set the socket factory then you can configure a custom socket factory that uses the specific proxy you want.

如果可以设置套接字工厂,则可以配置使用所需特定代理的自定义套接字工厂。

#2


9  

I recommend using a custom ProxySelector. I had the same problem and it works great and is super flexible. It's simple too.

我建议使用自定义ProxySelector。我有同样的问题,它很有效,而且非常灵活。这也很简单。

Here's my CustomProxySelector:

这是我的CustomProxySelector:

import org.hibernate.validator.util.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.*;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

/**
 * So the way a ProxySelector works is that for all Connections made,
 * it delegates to a proxySelector(There is a default we're going to
 * override with this class) to know if it needs to use a proxy
 * for the connection.
 * <p>This class was specifically created with the intent to proxy connections
 * going to the allegiance soap service.</p>
 *
 * @author Nate
 */
class CustomProxySelector extends ProxySelector {

private final ProxySelector def;

private Proxy proxy;

private static final Logger logger = Logger.getLogger(CustomProxySelector.class.getName());

private List<Proxy> proxyList = new ArrayList<Proxy>();

/*
 * We want to hang onto the default and delegate
 * everything to it unless it's one of the url's
 * we need proxied.
 */
CustomProxySelector(String proxyHost, String proxyPort) {
    this.def = ProxySelector.getDefault();
    proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, (null == proxyPort) ? 80 : Integer.valueOf(proxyPort)));
    proxyList.add(proxy);
    ProxySelector.setDefault(this);
}

@Override
public List<Proxy> select(URI uri) {
    logger.info("Trying to reach URL : " + uri);
    if (uri == null) {
        throw new IllegalArgumentException("URI can't be null.");
    }
    if (uri.getHost().contains("allegiancetech")) {
        logger.info("We're trying to reach allegiance so we're going to use the extProxy.");
        return proxyList;
    }
    return def.select(uri);
}

/*
* Method called by the handlers when it failed to connect
* to one of the proxies returned by select().
*/
@Override
public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
    logger.severe("Failed to connect to a proxy when connecting to " + uri.getHost());
    if (uri == null || sa == null || ioe == null) {
        throw new IllegalArgumentException("Arguments can't be null.");
    }
    def.connectFailed(uri, sa, ioe);
}

}