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

发布于 2024-08-19 16:11:38 字数 5508 浏览 1 评论 0原文

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

在一个小测试应用程序中,我尝试通过 URL.openConnection() 下载网页,然后用我自己的代理选择器替换默认的代理选择器。但这会导致异常:

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

  1. 问题:“如果我的 ProxySelector 仅返回 HTTP 代理,为什么尝试应用程序通过 SOCKS 建立连接?”

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

I am developing a Java webservice application (with JAX-WS) that has to use two different proxies to establish separated connections to internet and an intranet. As solution I tried to write my own java.net.ProxySelector that returns a java.net.Proxy instance (of type HTTP) for internet or intranet.

In a little test application I try to download webpage via URL.openConnection(), and before I replaced the default ProxySelector with my own. But it results in an exception:

java.net.SocketException: Unknown proxy type : HTTP
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:370)
at java.net.Socket.connect(Socket.java:519)
at java.net.Socket.connect(Socket.java:469)
at sun.net.NetworkClient.doConnect(NetworkClient.java:163)
at sun.net.www.http.HttpClient.openServer(HttpClient.java:394)
at sun.net.www.http.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)
at norman.test.ProxyTest.main(ProxyTest.java:65)

  1. Question: "Why tries the application to establish a connection via SOCKS, if my ProxySelector only returns a HTTP Proxy?"

2 Question: "Is there a alternative, to define different proxies for each connection?"

This is my 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);
}
}

This is the test class:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

很酷不放纵 2024-08-26 16:11:38

好的,我已经找到问题了。

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

首先,HttpURLConnection 使用 URI 调用 select(),Scheme 为“http”但没有端口。 select() 检查主机地址和端口是否与 IntranetAddress 或 ExtranetAddress 相同。这不匹配,因为未给出端口。因此选择返回一个用于直接连接的代理。

第二次 HttpURLConnection 使用 URI、“socket”方案和端口 80 调用 select()。因此,因为 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("https")){
                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()。

Ok, I have found the problem.

The HttpURLConnection did the OwnProxySelector.select() twice if the requested URL does not contain a port.

At first, HttpURLConnection invoked the select() with an URI, with the Scheme of "http" but no port. The select() checks whether the host address and port are euqal to intranetAddress or extranetAddress. This didn't match, because the port was not given. So the select return a Proxy for a direct connection.

At the second HttpURLConnection invoked the select() with an URI, with the Scheme of "socket" and port 80. So, because the select() checks host address and port, but not the scheme, it returned a HTTP proxy.

Now here is my corrected version of OwnProxySelector. It checks the scheme and sets the default port for HTTP or HTTPS if the port is not given by the URI. Also it asks the Java standard ProxySelector, if no HTTP or HTTPS scheme is given.

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

}

But it is curious to me, that the HttpURLConnection did a second invoke of select(), when it got a direct connection Proxy from the first invoke.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文