HttpClient和HtmlUnit的比较总结以及使用技巧(二)

来源


上一篇介绍了HtmlUnit在网络抓取,小型爬虫等应用中优劣势,这篇一起来看下HttpClient在这一方面的应用。

HttpClient 是 Apache Jakarta Common 下的子项目,可以用来提供高效的、最新的、功能丰富的支持 HTTP 协议客户端程工具包。它采用是大家再熟悉不过的Scoket编程,我们在HttpClientConnectionOperator类中可以看到。


[java]  view plain copy
  1. "font-size:14px;"public void connect(  
  2.             final ManagedHttpClientConnection conn,  
  3.             final HttpHost host,  
  4.             final InetSocketAddress localAddress,  
  5.             final int connectTimeout,  
  6.             final SocketConfig socketConfig,  
  7.             final HttpContext context) throws IOException {  
  8.                 // 它先去找找这个Socket工厂,看看有没有  
  9.         final Lookup registry = getSocketFactoryRegistry(context);  
  10.         final ConnectionSocketFactory sf = registry.lookup(host.getSchemeName());  
  11.         if (sf == null) {  
  12.             throw new UnsupportedSchemeException(host.getSchemeName() +  
  13.                     " protocol is not supported");  
  14.         }  
  15.         // InetAddress这货也在。。。  
  16.         final InetAddress[] addresses = this.dnsResolver.resolve(host.getHostName());  
  17.         final int port = this.schemePortResolver.resolve(host);  
  18.         for (int i = 0; i < addresses.length; i++) {  
  19.             final InetAddress address = addresses[i];  
  20.             final boolean last = i == addresses.length - 1;  
  21.   
  22.             Socket sock = sf.createSocket(context);  
  23.             sock.setReuseAddress(socketConfig.isSoReuseAddress());  
  24.             conn.bind(sock);  
  25.   
  26.             final InetSocketAddress remoteAddress = new InetSocketAddress(address, port);  
  27.             if (this.log.isDebugEnabled()) {  
  28.                 this.log.debug("Connecting to " + remoteAddress);  
  29.             }  
  30.             try {  
  31.                 sock.setSoTimeout(socketConfig.getSoTimeout());  
  32.                 // 这里就是它打开这个链接了,建立链接之后就可以接收流了,然后HttpClient再用自己的流接收方式接收进去。。。  
  33.                 sock = sf.connectSocket(  
  34.                         connectTimeout, sock, host, remoteAddress, localAddress, context);  
  35.                 sock.setTcpNoDelay(socketConfig.isTcpNoDelay());  
  36.                 sock.setKeepAlive(socketConfig.isSoKeepAlive());  
  37.                 final int linger = socketConfig.getSoLinger();  
  38.                 if (linger >= 0) {  
  39.                     sock.setSoLinger(linger > 0, linger);  
  40.                 }  
  41.                 conn.bind(sock);  
  42.                 if (this.log.isDebugEnabled()) {  
  43.                     this.log.debug("Connection established " + conn);  
  44.                 }  
  45.                 return;  
  46.             } catch (final SocketTimeoutException ex) {  
  47.                 if (last) {  
  48.                     throw new ConnectTimeoutException(ex, host, addresses);  
  49.                 }  
  50.             } catch (final ConnectException ex) {  
  51.                 if (last) {  
  52.                     final String msg = ex.getMessage();  
  53.                     if ("Connection timed out".equals(msg)) {  
  54.                         throw new ConnectTimeoutException(ex, host, addresses);  
  55.                     } else {  
  56.                         throw new HttpHostConnectException(ex, host, addresses);  
  57.                     }  
  58.                 }  
  59.             }  
  60.             if (this.log.isDebugEnabled()) {  
  61.                 this.log.debug("Connect to " + remoteAddress + " timed out. " +  
  62.                         "Connection will be retried using another IP address");  
  63.             }  
  64.         }  
  65.     }  
  66.   

就是说HttpClient和URLConnection一样是通过Socket编程来实现网络通信的,相比来说当然是JDK的东西效率什么的更高了,但是我们选择前者,其实就是主要原因就是因为----懒!HttpClient是对Socket/HTTP协议恰到好处的封装,它不像HtmlUnit那样高度,也不像URLConnection用起来比较麻烦,它兼有简单、强扩展等特性,所以和它同Apache Jakarta开发项目组的HtmlUnit也采用了HttpClient。

优点(从百科中说的优点来看):

         1、实现了所有 HTTP 的方法(GET,POST,PUT,HEAD 等):实现倒是实现了,笔者就用过GET、POST、PUT,其它的可能用的比较少了。现在Java Servlet服务器不是整天都GET、POST的,倒也不是特别关心其它的方式
          2、支持自动转向:这句话说的也点坑,因为它其实是想说,支持200以下的响应码自动向前,这点可以参考HttpRequestExecutor类中的doReceiveResponse方法。
        
[java]  view plain copy
  1. protected HttpResponse doReceiveResponse(  
  2.            final HttpRequest request,  
  3.            final HttpClientConnection conn,  
  4.            final HttpContext context) throws HttpException, IOException {  
  5.             // 他们老喜欢把这个检测写成Args类了。。。。  
  6.        Args.notNull(request, "HTTP request");  
  7.        Args.notNull(conn, "Client connection");  
  8.        Args.notNull(context, "HTTP context");  
  9.        HttpResponse response = null;  
  10.        int statusCode = 0;  
  11.        // 这里开始接收响应(路由已经在MainClientExec中的establishRoute建立并连接)  
  12.        // 它判断了下状态码是不是小于200,小于200就要继续接收    
  13.        while (response == null || statusCode < HttpStatus.SC_OK) {  
  14.   
  15.            response = conn.receiveResponseHeader();  
  16.            if (canResponseHaveBody(request, response)) {  
  17.                conn.receiveResponseEntity(response);  
  18.            }  
  19.            statusCode = response.getStatusLine().getStatusCode();  
  20.   
  21.        } // while intermediate response  
  22.   
  23.        return response;  
  24.    }  

最开始的时候我还以为是支持自动跳转,就像上一篇文章中的例子一样。
        3、支持 HTTPS 协议:HttpClient对SSL的支持是比较全面的,最简单的:
[java]  view plain copy
  1.     private static HttpClient getSSLInsecureClient() throws Exception {    
  2. 43.        // 建立一个认证上下文,认可所有安全链接,当然,这是因为我们仅仅是测试,实际中认可所有安全链接是危险的    
  3. 44.        SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(nullnew TrustStrategy() {    
  4. 45.            public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {    
  5. 46.                return true;    
  6. 47.            }    
  7. 48.        }).build();    
  8. 49.        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);    
  9. 50.        return HttpClients.custom().//    
  10. 51.                setSSLSocketFactory(sslsf)//    
  11. 52.                // .setProxy(new HttpHost("127.0.0.1", 8888))    
  12. 53.                .build();    
  13. 54.    }   
HttpClient还支持各种各样的证书验证方式,还有服务器认证,看这个就可以了: http://baike.baidu.com/view/2476238.htm?fr=aladdin

4、支持代理服务器:支持代理,就实用的,你可以把HttpClient的代理设置为Filder(一款功能非常强大的网络监听软件,WebDebugger),这样所有的HttpClient发出的请求都会被Filder所接收和管理,这是在代码测试阶段一个非常好的方式。


你可能感兴趣的:(htmlunit)