首页 文章

将不同的代理连接到特定地址

提问于
浏览
5

我正在开发一个Java Web服务应用程序(使用JAX-WS),它必须使用两个不同的代理来 Build 与Internet和Intranet的分离连接 . 作为解决方案,我尝试编写自己的java.net.ProxySelector,它返回一个用于Internet或Intranet的java.net.Proxy实例(HTTP类型) .

在一个小测试应用程序中,我尝试通过URL.openConnection()下载网页,然后我用我自己的替换默认的ProxySelector . 但它导致了一个例外:

java.net.SocketException:未知的代理类型:java.net.Socks.Socket.mpl上的java.net.SocksSocketImpl.connect(SocksSocketImpl.java:370)中的HTTP(Socket.java:519) (Socket.java:469)位于sun.net.www.http.HttpClient.openServer(HttpClient.java:394)sun.net.www.http的sun.net.NetworkClient.doConnect(NetworkClient.java:163) . HttpClient.openServer(HttpClient.java:529)at sun.net.www.http.HttpClient . (HttpClient.java:233)at sun.net.www.http.HttpClient.New(HttpClient.java:306)at sun . net.www.protocol.http.HttpURLConnection.getNewHttpClient(HttpURLConnection.java:844)at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:792)at sun.net.www.protocol.http . HttpURLConnection.connect(HttpURLConnection.java:703)at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1026)at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:373)at norman.test诺曼的.ProxyTest.conntectToRmViaProxy(ProxyTest.java:42) .test.ProxyTest.main(ProxyTest.java:65)

  • 问题:"Why tries the application to establish a connection via SOCKS, if my ProxySelector only returns a HTTP Proxy?"

2问题:“是否有替代方案,为每个连接定义不同的代理?”

这是我的ProxySelector:

public class OwnProxySelector extends ProxySelector {
private Proxy intranetProxy;
private Proxy extranetProxy;
private Proxy directConnection = Proxy.NO_PROXY;
private URI intranetAddress;
private URI extranetAddress;

/* (non-Javadoc)
 * @see java.net.ProxySelector#connectFailed(java.net.URI, java.net.SocketAddress, java.io.IOException)
 */
public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
    // Nothing to do
}

/* (non-Javadoc)
 * @see java.net.ProxySelector#select(java.net.URI)
 */
public List select(URI uri) {
    ArrayList<Proxy> result = new ArrayList<Proxy>();

    if(intranetAddress.getHost().equals(uri.getHost()) && intranetAddress.getPort()==uri.getPort()){
        result.add(intranetProxy);
        System.out.println("Adding intranet Proxy!");
    }
    else if(extranetAddress.getHost().equals(uri.getHost()) && extranetAddress.getPort()==uri.getPort()){
        result.add(extranetProxy);
        System.out.println("Adding extranet Proxy!");
    }
    else{
        result.add(directConnection);
        System.out.println("Adding direct connection!");
    }

    return result;
}

public void setIntranetProxy(String proxyAddress, int proxyPort){
    if(proxyAddress==null || proxyAddress.isEmpty()){
        intranetProxy = Proxy.NO_PROXY;
    }
    else{
        SocketAddress address = new InetSocketAddress(proxyAddress, proxyPort);
        intranetProxy = new Proxy(Proxy.Type.HTTP, address);
    }
}

public void setExtranetProxy(String proxyAddress, int proxyPort){
    if(proxyAddress==null || proxyAddress.isEmpty()){
        extranetProxy = Proxy.NO_PROXY;
    }
    else{
        SocketAddress address = new InetSocketAddress(proxyAddress, proxyPort);
        extranetProxy = new Proxy(Proxy.Type.HTTP, address);
    }
}

public void clearIntranetProxy(){
    intranetProxy = Proxy.NO_PROXY;
}

public void clearExtranetProxy(){
    extranetProxy = Proxy.NO_PROXY;
}

public void setIntranetAddress(String address) throws URISyntaxException{
    intranetAddress = new URI(address);
}

public void setExtranetAddress(String address) throws URISyntaxException{
    extranetAddress = new URI(address);
}
}

这是测试类:

public class ProxyTest {
OwnProxySelector ownSelector = new OwnProxySelector();

public ProxyTest(){
    ownSelector.setIntranetProxy("intranet.proxy", 8123);
    try {
        ownSelector.setIntranetAddress("http://intranet:80");
    } catch (URISyntaxException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    ownSelector.setExtranetProxy("", 0);
    try {
        ownSelector.setExtranetAddress("http://www.example.com:80");
    } catch (URISyntaxException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }


    ProxySelector.setDefault(ownSelector);
}

public void conntectToRmViaProxy(boolean internal, String connectAddress){
    try {
        URL url = new URL(connectAddress);

        HttpURLConnection conn = (HttpURLConnection)url.openConnection();

        conn.setRequestMethod("GET");
          if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {
            System.out.println(conn.getResponseMessage());
          }
          else{
              BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
              int tmp = reader.read();
              while(tmp != -1){
                  System.out.print((char)tmp);
                  tmp = reader.read();
              }
          }

    } catch (MalformedURLException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

public static void main(String[] args){
    ProxyTest proxyText = new ProxyTest();
    proxyText.conntectToRmViaProxy(true, "http://intranet:80");
}
}

1 回答

  • 5

    好的,我发现了问题 .

    如果请求的URL不包含端口,HttpURLConnection会执行两次OwnProxySelector.select() .

    首先,HttpURLConnection使用URI调用select(),其Scheme为“http”但没有端口 . select()检查主机地址和端口是否与intranetAddress或extranetAddress相同 . 这不匹配,因为没有给出端口 . 因此,select为直接连接返回一个Proxy .

    在第二个HttpURLConnection调用带有URI的select(),方案是“socket”和端口80.因此,因为select()检查主机地址和端口,而不是方案,它返回了一个HTTP代理 .

    现在这是我更正的OwnProxySelector版本 . 它检查方案并设置HTTP或HTTPS的默认端口(如果URI未给出端口) . 如果没有给出HTTP或HTTPS方案,它也会询问Java标准ProxySelector .

    public class OwnProxySelector extends ProxySelector {
    private ProxySelector defaultProxySelector;
    private Proxy intranetProxy;
    private Proxy extranetProxy;
    private Proxy directConnection = Proxy.NO_PROXY;
    private URI intranetAddress;
    private URI extranetAddress;
    
    
    public OwnProxySelector(ProxySelector defaultProxySelector){
        this.defaultProxySelector = defaultProxySelector;
    }
    
    /* (non-Javadoc)
     * @see java.net.ProxySelector#connectFailed(java.net.URI, java.net.SocketAddress, java.io.IOException)
     */
    public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
        // Nothing to do
    }
    
    /* (non-Javadoc)
     * @see java.net.ProxySelector#select(java.net.URI)
     */
    public List select(URI uri) {
        ArrayList<Proxy> result = new ArrayList<Proxy>();
    
        if(uri.getScheme().equalsIgnoreCase("http") || uri.getScheme().equalsIgnoreCase("https")){
            int uriPort = uri.getPort();
    
            // set default http and https ports if port is not given in URI
            if(uriPort<1){
                if(uri.getScheme().equalsIgnoreCase("http")){
                    uriPort = 80;
                }
                else if(uri.getScheme().equalsIgnoreCase("http")){
                    uriPort = 443;
                }
            }
    
            if(intranetAddress.getHost().equals(uri.getHost()) && intranetAddress.getPort()==uriPort){
                result.add(intranetProxy);
                System.out.println("Adding intranet Proxy!");
            }
            else if(extranetAddress.getHost().equals(uri.getHost()) && extranetAddress.getPort()==uriPort){
                result.add(extranetProxy);
                System.out.println("Adding extranet Proxy!");
            }
        }
    
        if(result.isEmpty()){
            List<Proxy> defaultResult = defaultProxySelector.select(uri);
            if(defaultResult!=null && !defaultResult.isEmpty()){
                result.addAll(defaultResult);
                System.out.println("Adding Proxis from default selector.");
            }
            else{
                result.add(directConnection);
                System.out.println("Adding direct connection, because requested URI does not match any Proxy");
            }
        }
    
        return result;
    }
    
    public void setIntranetProxy(String proxyAddress, int proxyPort){
        if(proxyAddress==null || proxyAddress.isEmpty()){
            intranetProxy = Proxy.NO_PROXY;
        }
        else{
            SocketAddress address = new InetSocketAddress(proxyAddress, proxyPort);
            intranetProxy = new Proxy(Proxy.Type.HTTP, address);
        }
    }
    
    public void setExtranetProxy(String proxyAddress, int proxyPort){
        if(proxyAddress==null || proxyAddress.isEmpty()){
            extranetProxy = Proxy.NO_PROXY;
        }
        else{
            SocketAddress address = new InetSocketAddress(proxyAddress, proxyPort);
            extranetProxy = new Proxy(Proxy.Type.HTTP, address);
        }
    }
    
    public void clearIntranetProxy(){
        intranetProxy = Proxy.NO_PROXY;
    }
    
    public void clearExtranetProxy(){
        extranetProxy = Proxy.NO_PROXY;
    }
    
    public void setIntranetAddress(String address) throws URISyntaxException{
        intranetAddress = new URI(address);
    }
    
    public void setExtranetAddress(String address) throws URISyntaxException{
        extranetAddress = new URI(address);
    }
    

    }

    但是我很好奇,当HttpURLConnection从第一次调用获得直接连接代理时,它执行了select()的第二次调用 .

相关问题