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

Posted

技术标签:

【中文标题】如何在不设置系统范围属性的情况下将 HTTP 代理用于 JAX-WS 请求?【英文标题】:How can I use an HTTP proxy for a JAX-WS request without setting a system-wide property? 【发布时间】:2011-09-20 18:52:36 【问题描述】:

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

可以通过设置系统范围的值(例如系统属性)来做到这一点:

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

或者通过设置默认的 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));

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

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

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

【问题讨论】:

为什么要在一台服务器上拥有多个代理? 【参考方案1】:

如果您使用的是 JAX-WS,您可能能够设置底层 HttpURLConnection 使用的套接字工厂。我看到模糊的迹象表明这对于 SSL 是可能的(请参阅HTTPS SSLSocketFactory),但我不确定您是否可以对常规 HTTP 连接执行此操作(或者坦率地说,这甚至是如何工作的:他们引用的 JAXWSProperties 类似乎不是-标准 JDK 类)。

如果您可以设置套接字工厂,那么您可以配置使用您想要的特定代理的自定义套接字工厂。

【讨论】:

我的 JDK 1.6 中似乎不存在 JAXWSProperties 您的方法确实有效,并且我们确实成功地实现了它,但我决定使用支持的 API 和使用 HttpsURLConnection.setDefaultSSLSocketFactory() 的 JVM 范围的 SSLSocketFactory 设置。我们会将任何密钥和证书组合到默认密钥库和信任库的单个版本中。 您介意分享一些有关您实施 Femi 建议的细节吗? 该链接没有任何内容,而是找到了这个。 metro.java.net/2.1.1/guide/HTTPS_SSLSocketFactory.html 有谁知道如何为非 SSL 传输做到这一点?【参考方案2】:

我建议使用自定义 ProxySelector。我遇到了同样的问题,它工作得很好,而且非常灵活。也很简单。

这是我的 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);
    

【讨论】:

我认为这与我使用 MyProxySelector 的方法相似。 如何解决线程所有者描述的关于在系统范围内设置代理的问题?对我来说,它似乎只是 ProxySelector.setDefault 的一个包装器,实际上是系统范围的设置。 @Emdee 你说得对,它是一个系统范围的代理选择器,因为每个请求都会通过它——但是你可以根据你要去的 URI 来查看它可以选择不同的代理(或无代理)或任何您需要的。这就是它的美妙之处——它很灵活,让您可以根据您从哪里提取信息来使用您需要的任何东西。尽管在这种情况下,默认值恰好与所选的相同。不一定非要这样——它是一个框架,可以让你选择任何你想要的东西。

以上是关于如何在不设置系统范围属性的情况下将 HTTP 代理用于 JAX-WS 请求?的主要内容,如果未能解决你的问题,请参考以下文章

如何在不丢失setfocus的情况下将光标设置到文本框的末尾?

如何在不使用ViewData的情况下将对象属性绑定到DropDownList中的数据源

如何在不调用 [关闭] 的情况下将整数从控制器设置到子视图

如何在不覆盖 TTY 的情况下将密码传递给 su/sudo/ssh?

如何在不出现 ORA-01460:未实现或不合理的转换错误的情况下将大字符串设置为参数?

如何在不从当前活动选项卡中获取焦点的情况下将子窗口添加到 QMdiArea(设置为 TAB 模式)?