Apache Http Client 4.0.1 SSL代理

时间:2014-03-12 05:58:18

标签: java apache ssl httpclient apache-httpclient-4.x

我正在使用Apache Http客户端4.0.1与服务器进行通信。我已经有一个安全/非安全的客户端代码,可以正常工作。

最近新添加的是为此代码添加代理,所以我添加了以下代码来执行此操作(当前非安全代理),

 HttpHost proxy = new HttpHost("localhost", 5555);
 httpClient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);

这在非安全请求中运行良好。但是我在使用相同代码的安全(https)请求时遇到问题。

获取以下异常(它在失败前尝试了几次),

Mar 12, 2014 11:14:27 AM org.apache.http.impl.client.DefaultRequestDirector tryConnect
INFO: I/O exception (org.apache.http.NoHttpResponseException) caught when connecting to the target host: The target server failed to respond
Mar 12, 2014 11:14:27 AM org.apache.http.impl.client.DefaultRequestDirector tryConnect
INFO: Retrying connect
org.apache.http.NoHttpResponseException: The target server failed to respond
    at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:95)
    at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:62)
    at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:254)
    at org.apache.http.impl.AbstractHttpClientConnection.receiveResponseHeader(AbstractHttpClientConnection.java:289)
    at org.apache.http.impl.conn.DefaultClientConnection.receiveResponseHeader(DefaultClientConnection.java:252)
    at org.apache.http.impl.conn.ManagedClientConnectionImpl.receiveResponseHeader(ManagedClientConnectionImpl.java:191)
    at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:300)
    at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:127)
    at org.apache.http.impl.client.DefaultRequestDirector.createTunnelToTarget(DefaultRequestDirector.java:899)
    at org.apache.http.impl.client.DefaultRequestDirector.establishRoute(DefaultRequestDirector.java:818)
    at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:644)
    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:479)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:906)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:805)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:784)
    at com.poc.test.SSLTest.main(SSLTest.java:88)

尝试了以下事项,

  1. 对于https请求,我使用与“https”相同的SSLFactory将“http”和“https”添加到架构注册表中。
  2. 将代理更改为, HttpHost proxy = new HttpHost(“localhost”,5555,“https”);
  3. 然而,在这两种情况下都失败了,

    javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
        at sun.security.ssl.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:397)
        at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:128)
        at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:572)
        at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:180)
        at org.apache.http.impl.conn.ManagedClientConnectionImpl.open(ManagedClientConnectionImpl.java:294)
        at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:640)
        at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:479)
        at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:906)
        at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:805)
        at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:784)
        at com.poc.test.SSLTest.main(SSLTest.java:89)
    

    注意 - 我通过tcpmon在我的localhost上运行非安全代理。

    编辑:这是我用于代理通信的SSL的代码,

    DefaultHttpClient httpClient = new DefaultHttpClient();
    
    try {
        SSLContext ctx = SSLContext.getInstance("TLSv1.1");
        TrustManager[] trustManagers = getTrustManagers("jks", new FileInputStream(new File("C:\\SSLKeyStore.ks")), "changeit");
        ctx.init(null, trustManagers, new SecureRandom());
    
        HttpGet httpget = new HttpGet("https://localhost:8844/Channels/HTTP/getData");
        System.out.println("executing request" + httpget.getRequestLine());
    
        SSLSocketFactory factory = new SSLSocketFactory(ctx);
        factory.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
    
        ClientConnectionManager manager = httpClient.getConnectionManager();
        manager.getSchemeRegistry().register(new Scheme("https", 443, factory));
        manager.getSchemeRegistry().register(new Scheme("http", 80, PlainSocketFactory.getSocketFactory()));
    
        HttpHost proxy = new HttpHost("localhost", 5555, "http");
        httpClient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);
    
        HttpResponse response = httpClient.execute(httpget);
        HttpEntity entity = response.getEntity();
    
        System.out.println("----------------------------------------");
        System.out.println(response.getStatusLine());
        if (entity != null) {
            System.out.println("Response content length: " + entity.getContentLength());
        }
        EntityUtils.consume(entity);
    } catch (Exception exception) {
        exception.printStackTrace();
    } finally {
        httpClient.getConnectionManager().shutdown();
    }
    

    有关正在发生的事情的任何想法,我在https和代理方面缺少什么。

    最新编辑 - 甚至尝试了他们的示例代码(ClientExecuteProxy.java),它也失败了代理。这个功能坏了吗?

    HttpHost proxy = new HttpHost("127.0.0.1", 8080, "http");
    
        DefaultHttpClient httpclient = new DefaultHttpClient();
        try {
            httpclient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);
    
            HttpHost target = new HttpHost("issues.apache.org", 443, "https");
            HttpGet req = new HttpGet("/");
    
            System.out.println("executing request to " + target + " via " + proxy);
            HttpResponse rsp = httpclient.execute(target, req);
            HttpEntity entity = rsp.getEntity();
    
            System.out.println("----------------------------------------");
            System.out.println(rsp.getStatusLine());
            Header[] headers = rsp.getAllHeaders();
            for (int i = 0; i<headers.length; i++) {
                System.out.println(headers[i]);
            }
            System.out.println("----------------------------------------");
    
            if (entity != null) {
                System.out.println(EntityUtils.toString(entity));
            }
    
        } finally {
            // When HttpClient instance is no longer needed,
            // shut down the connection manager to ensure
            // immediate deallocation of all system resources
            httpclient.getConnectionManager().shutdown();
        }
    }
    

    谢谢, 维基

1 个答案:

答案 0 :(得分:0)

我不知道你是在处理证书信托问题。

虽然没有看到你如何具体建立连接,但我可以毫不确定地说。

“未经过身份验证的对等体”意味着无法验证一个或多个服务器所提供的证书验证。

修改 由于代理权在您的控制之下,因此您目前具有很大的灵活性。

请参阅this SO article,它可能符合您的需求。