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

问题描述 投票:0回答:3

我有一个应用程序需要向 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.Proxy
对象,就像
java.net.Socket(java.net.Proxy proxy)
构造函数一样。 这样,必要的设置就位于需要设置它们的系统部分的本地。 有没有办法用 JAX-WS 来做到这一点?

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

java http soap proxy jax-ws
3个回答
16
投票

我建议使用自定义 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);
    }
}

5
投票

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

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


0
投票

您需要将自定义处理程序添加到绑定HandlerChain(此方法仅适用于 JAX-WS 参考实现并使用反射)

BindingProvider bindingProvider = (BindingProvider) getYouBindingProviderHere();
List<Handler> handlerChain = binding.getHandlerChain();
String proxyHost = proxyHostHere;
int proxyPort = proxyPortHere;
handlerChain.add(new SetProxyHandler(proxyHost, proxyPort));
binding.setHandlerChain(handlerChain);

和 SetProxyHandler 类

import com.sun.xml.ws.api.EndpointAddress;
import com.sun.xml.ws.api.message.Packet;
import com.sun.xml.ws.handler.MessageUpdatableContext;
import com.sun.xml.ws.handler.SOAPMessageContextImpl;

import javax.xml.namespace.QName;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
import java.lang.reflect.Field;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.util.HashSet;
import java.util.Set;


public class SetProxyHandler implements SOAPHandler<SOAPMessageContext> {

    private static final Field packetField;
    private static final Field proxyField;

    static {
        try {
            packetField = MessageUpdatableContext.class.getDeclaredField("packet");
            packetField.setAccessible(true);
            proxyField = EndpointAddress.class.getDeclaredField("proxy");
            proxyField.setAccessible(true);
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        }
    }

    private final Proxy proxy;

    SetProxyHandler(String proxyHost, int proxyPort) {
        this.proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort));
    }

    @Override
    public Set<QName> getHeaders() {
        return new HashSet<QName>();
    }

    @Override
    public boolean handleMessage(SOAPMessageContext context) {
        boolean isRequest = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
        if (isRequest) {
            if (context instanceof SOAPMessageContextImpl) {
               com.sun.xml.ws.transport.http.client.HttpClientTransport.createHttpConnection
                try {
                    Packet packet = (Packet) packetField.get(context);
                    if (packet != null) {
                        EndpointAddress endpointAddress = packet.endpointAddress;
                        if (endpointAddress != null) {
                            proxyField.set(endpointAddress, proxy);
                        }
                    }

                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                }
            }
        }

        return true;
    }

    @Override
    public boolean handleFault(SOAPMessageContext context) {
        return true;
    }

    @Override
    public void close(MessageContext context) {
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.