`
liuxinglanyue
  • 浏览: 564804 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

HttpClient 学习整理

阅读更多

来自:深沉的船

HttpClient 是我最近想研究的东西,以前想过的一些应用没能有很好的实现,发现这个开源项目之后就有点眉目了,令人头痛的cookie问题还是有办法解决滴。在网上整理了一些东西,写得很好,寄放在这里。

HTTP 协议可能是现在 Internet 上使用得最多、最重要的协议了,越来越多的 Java 应用程序需要直接通过 HTTP 协议来访问网络资源。虽然在 JDK 的 java.net 包中已经提供了访问 HTTP 协议的基本功能,但是对于大部分应用程序来说,JDK 库本身提供的功能还不够丰富和灵活。HttpClient 是 Apache Jakarta Common 下的子项目,用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。HttpClient 已经应用在很多的项目中,比如 Apache Jakarta 上很著名的另外两个开源项目 Cactus 和 HTMLUnit 都使用了 HttpClient,更多使用 HttpClient 的应用可以参见http://wiki.apache.org/jakarta-httpclient/HttpClientPowered。HttpClient 项目非常活跃,使用的人还是非常多的。目前 HttpClient 版本是在 2005.10.11 发布的 3.0 RC4 。

------------------------------------

应用HttpClient来对付各种顽固的WEB服务器

一般的情况下我们都是使用IE或者Navigator浏览器来访问一个WEB服务器,用来浏览页面查看信息或者提交一些数据等等。所访问的这些页面有的仅仅是一些普通的页面,有的需要用户登录后方可使用,或者需要认证以及是一些通过加密方式传输,例如HTTPS。目前我们使用的浏览器处理这些情况都不会构成问题。不过你可能在某些时候需要通过程序来访问这样的一些页面,比如从别人的网页中“偷”一些数据;利用某些站点提供的页面来完成某种功能,例如说我们想知道某个手机号码的归属地而我们自己又没有这样的数据,因此只好借助其他公司已有的网站来完成这个功能,这个时候我们需要向网页提交手机号码并从返回的页面中解析出我们想要的数据来。如果对方仅仅是一个很简单的页面,那我们的程序会很简单,本文也就没有必要大张旗鼓的在这里浪费口舌。但是考虑到一些服务授权的问题,很多公司提供的页面往往并不是可以通过一个简单的URL就可以访问的,而必须经过注册然后登录后方可使用提供服务的页面,这个时候就涉及到 COOKIE问题的处理。我们知道目前流行的动态网页技术例如ASP、JSP无不是通过COOKIE来处理会话信息的。为了使我们的程序能使用别人所提供的服务页面,就要求程序首先登录后再访问服务页面,这过程就需要自行处理cookie,想想当你用java.net.HttpURLConnection 来完成这些功能时是多么恐怖的事情啊!况且这仅仅是我们所说的顽固的WEB服务器中的一个很常见的“顽固”!再有如通过HTTP来上传文件呢?不需要头疼,这些问题有了“它”就很容易解决了!


我们不可能列举所有可能的顽固,我们会针对几种最常见的问题进行处理。当然了,正如前面说到的,如果我们自己使用java.net.HttpURLConnection来搞定这些问题是很恐怖的事情,因此在开始之前我们先要介绍一下一个开放源码的项目,这个项目就是Apache开源组织中的httpclient,它隶属于Jakarta的commons项目,目前的版本是2.0RC2。commons下本来已经有一个net的子项目,但是又把httpclient单独提出来,可见http服务器的访问绝非易事。

Commons-httpclient项目就是专门设计来简化HTTP客户端与服务器进行各种通讯编程。通过它可以让原来很头疼的事情现在轻松的解决,例如你不再管是HTTP或者HTTPS的通讯方式,告诉它你想使用HTTPS方式,剩下的事情交给httpclient替你完成。本文会针对我们在编写HTTP客户端程序时经常碰到的几个问题进行分别介绍如何使用httpclient来解决它们,为了让读者更快的熟悉这个项目我们最开始先给出一个简单的例子来读取一个网页的内容,然后循序渐进解决掉前进中的所有问题。

1. 读取网页(HTTP/HTTPS)内容

下面是我们给出的一个简单的例子用来访问某个页面

 

/* 
* Created on 2009-8-11 by skydong 
*/ 
 
package http.demo; 
import java.io.IOException; 
import org.apache.commons.httpclient.*; 
import org.apache.commons.httpclient.methods.*; 
 
/**  
 *最简单的HTTP客户端,用来演示通过GET或者POST方式访问某个页面 
  *@author skydong 
*/ 
 
public class SimpleClient { 
public static void main(String[] args) throws IOException 
{ 
  HttpClient client = new HttpClient(); 
      // 设置代理服务器地址和端口       
 
      //client.getHostConfiguration().setProxy("proxy_host_addr",proxy_port);  
      // 使用 GET 方法 ,如果服务器需要通过 HTTPS 连接,那只需要将下面 URL 中的 http 换成 https 
         HttpMethodmethod=newGetMethod("http://java.sun.com"); 
      //使用POST方法 
      //HttpMethod method = new PostMethod("http://java.sun.com"); 
      client.executeMethod(method); 
 
      //打印服务器返回的状态 
       System.out.println(method.getStatusLine()); 
      //打印返回的信息 
      System.out.println(method.getResponseBodyAsString()); 
      //释放连接 
      method.releaseConnection(); 
   } 
} 

 在这个例子中首先创建一个HTTP客户端(HttpClient)的实例,然后选择提交的方法是GET或者POST,最后在HttpClient实例上执行提交的方法,最后从所选择的提交方法中读取服务器反馈回来的结果。这就是使用HttpClient的基本流程。其实用一行代码也就可以搞定整个请求的过程,非常的简单!



2. 以GET或者POST方式向网页提交参数

其实前面一个最简单的示例中我们已经介绍了如何使用GET或者POST方式来请求一个页面,本小节与之不同的是多了提交时设定页面所需的参数,我们知道如果是GET的请求方式,那么所有参数都直接放到页面的URL后面用问号与页面地址隔开,每个参数用&隔开,例如:http://java.sun.com/?name=liudong&mobile=123456,但是当使用POST方法时就会稍微有一点点麻烦。本小节的例子演示向如何查询手机号码所在的城市,代码如下:

 

/* 
* Created on 2009-8-11 by skydong  
*/ 
 
package http.demo; 
import java.io.IOException; 
import org.apache.commons.httpclient.*; 
import org.apache.commons.httpclient.methods.*; 
 
  
 
/**  
 *提交参数演示 
 *该程序连接到一个用于查询手机号码所属地的页面 
 *以便查询号码段1330227所在的省份以及城市 
 *@author skydong 
 */ 
 
public class SimpleHttpClient {  
   public static void main(String[] args) throws IOException { 
      HttpClient client = new HttpClient(); 
      client.getHostConfiguration().setHost( "www.imobile.com.cn" , 80, "http" ); 
      method = getPostMethod();    // 使用 POST 方式提交数据  
      client.executeMethod(method);   //打印服务器返回的状态  
      System.out.println(method.getStatusLine());   //打印结果页面 
      String response=new String(method.getResponseBodyAsString().getBytes("8859_1")); 
 
      //打印返回的信息 
      System.out.println(response); 
      method.releaseConnection(); 
   } 
 
   /**  
    * 使用 GET 方式提交数据  
    *@return  
    */ 
 
   privatestaticHttpMethodgetGetMethod(){ 
      return new GetMethod("/simcard.php?simcard=1330227"); 
   } 
 
  
 
    /**  
     * 使用 POST 方式提交数据  
     *@return  
     */ 
 
  
 
    private static HttpMethod getPostMethod(){ 
      PostMethod post = new PostMethod( "/simcard.php" ); 
      NameValuePair simcard = new NameValuePair( "simcard" , "1330227" ); 
      post.setRequestBody( new NameValuePair[] { simcard}); 
      return post; 
   } 
}

 在上面的例子中页面http://www.imobile.com.cn/simcard.php需要一个参数是simcard,这个参数值为手机号码段,即手机号码的前七位,服务器会返回提交的手机号码对应的省份、城市以及其他详细信息。GET的提交方法只需要在URL后加入参数信息,而POST则需要通过NameValuePair类来设置参数名称和它所对应的值。


3. 处理页面重定向

在 JSP/Servlet编程中response.sendRedirect方法就是使用HTTP协议中的重定向机制。它与JSP中的的区别在于后者是在服务器中实现页面的跳转,也就是说应用容器加载了所要跳转的页面的内容并返回给客户端;而前者是返回一个状态码,这些状态码的可能值见下表,然后客户端读取需要跳转到的页面的URL并重新加载新的页面。就是这样一个过程,所以我们编程的时候就要通过 HttpMethod.getStatusCode()方法判断返回值是否为下表中的某个值来判断是否需要跳转。如果已经确认需要进行页面跳转了,那么可以通过读取HTTP头中的location属性来获取新的地址。

下面的代码片段演示如何处理页面的重定向

 

client.executeMethod(post); 
System.out.println(post.getStatusLine().toString()); 
post.releaseConnection(); 
// 检查是否重定向 
int statuscode = post.getStatusCode(); 
if ((statuscode == HttpStatus.SC_MOVED_TEMPORARILY) || (statuscode == HttpStatus.SC_MOVED_PERMANENTLY) || (statuscode == HttpStatus.SC_SEE_OTHER) || (statuscode == HttpStatus.SC_TEMPORARY_REDIRECT)) { 
// 读取新的 URL 地址  
   Headerheader=post.getResponseHeader("location"); 
   if (header!=null){ 
      Stringnewuri=header.getValue(); 
      if((newuri==null)||(newuri.equals(""))) 
         newuri="/"; 
         GetMethodredirect=newGetMethod(newuri); 
         client.executeMethod(redirect); 
         System.out.println("Redirect:"+redirect.getStatusLine().toString()); 
         redirect.releaseConnection(); 
   }else  
    System.out.println("Invalid redirect"); 
} 

 我们可以自行编写两个JSP页面,其中一个页面用response.sendRedirect方法重定向到另外一个页面用来测试上面的例子。


4. 模拟输入用户名和口令进行登录

本小节应该说是HTTP客户端编程中最常碰见的问题,很多网站的内容都只是对注册用户可见的,这种情况下就必须要求使用正确的用户名和口令登录成功后,方可浏览到想要的页面。因为HTTP协议是无状态的,也就是连接的有效期只限于当前请求,请求内容结束后连接就关闭了。在这种情况下为了保存用户的登录信息必须使用到Cookie机制。以JSP/Servlet为例,当浏览器请求一个JSP或者是Servlet的页面时,应用服务器会返回一个参数,名为 jsessionid(因不同应用服务器而异),值是一个较长的唯一字符串的Cookie,这个字符串值也就是当前访问该站点的会话标识。浏览器在每访问该站点的其他页面时候都要带上jsessionid这样的Cookie信息,应用服务器根据读取这个会话标识来获取对应的会话信息。

对于需要用户登录的网站,一般在用户登录成功后会将用户资料保存在服务器的会话中,这样当访问到其他的页面时候,应用服务器根据浏览器送上的Cookie中读取当前请求对应的会话标识以获得对应的会话信息,然后就可以判断用户资料是否存在于会话信息中,如果存在则允许访问页面,否则跳转到登录页面中要求用户输入帐号和口令进行登录。这就是一般使用JSP开发网站在处理用户登录的比较通用的方法。

这样一来,对于HTTP的客户端来讲,如果要访问一个受保护的页面时就必须模拟浏览器所做的工作,首先就是请求登录页面,然后读取Cookie值;再次请求登录页面并加入登录页所需的每个参数;最后就是请求最终所需的页面。当然在除第一次请求外其他的请求都需要附带上Cookie信息以便服务器能判断当前请求是否已经通过验证。说了这么多,可是如果你使用httpclient的话,你甚至连一行代码都无需增加,你只需要先传递登录信息执行登录过程,然后直接访问想要的页面,跟访问一个普通的页面没有任何区别,因为类HttpClient已经帮你做了所有该做的事情了,太棒了!下面的例子实现了这样一个访问的过程。

 

/* 
* Created on 2009-8-11 by Liudong 
*/ 
 
package http.demo; 
import org.apache.commons.httpclient.*; 
import org.apache.commons.httpclient.cookie.*; 
import org.apache.commons.httpclient.methods.*; 
 
/** 
 * 用来演示登录表单的示例 
 * @author skydong 
 */ 
 
public class FormLoginDemo { 
   static final String LOGON_SITE = "localhost" ; 
   static final int     LOGON_PORT = 8080; 
 
   public static void main(String[] args) throws Exception{ 
      HttpClient client = new HttpClient(); 
      client.getHostConfiguration().setHost(LOGON_SITE, LOGON_PORT); 
 
      // 模拟登录页面 login.jsp->main.jsp 
      PostMethod post = new PostMethod( "/main.jsp" ); 
      NameValuePair name = new NameValuePair( "name" , "ld" ); 
      NameValuePair pass = new NameValuePair( "password" , "ld" ); 
      post.setRequestBody( new NameValuePair[]{name,pass}); 
      int status = client.executeMethod(post); 
      System.out.println(post.getResponseBodyAsString()); 
      post.releaseConnection(); 
 
      // 查看 cookie 信息 
      CookieSpec cookiespec = CookiePolicy.getDefaultSpec(); 
      Cookie[] cookies = cookiespec.match(LOGON_SITE, LOGON_PORT, "/" , false , client.getState().getCookies()); 
      if (cookies.length == 0) { 
         System.out.println( "None" ); 
      } else { 
         for ( int i = 0; i < cookies.length; i++) { 
            System.out.println(cookies[i].toString()); 
         } 
      } 
 
      // 访问所需的页面 main2.jsp  
      GetMethodget=new GetMethod("/main2.jsp"); 
      client.executeMethod(get); 
      System.out.println(get.getResponseBodyAsString()); 
      get.releaseConnection(); 
   } 
} 

 5. 提交XML格式参数


提交XML格式的参数很简单,仅仅是一个提交时候的ContentType问题,下面的例子演示从文件文件中读取XML信息并提交给服务器的过程,该过程可以用来测试Web服务。

 

import java.io.File; 
import java.io.FileInputStream; 
import org.apache.commons.httpclient.HttpClient; 
import org.apache.commons.httpclient.methods.EntityEnclosingMethod; 
import org.apache.commons.httpclient.methods.PostMethod; 
 
  
 
/**  
 *用来演示提交XML格式数据的例子 
*/ 
 
public class PostXMLClient { 
 
   public static void main(String[] args) throws Exception { 
      File input = new File("test.xml"); 
      PostMethod post = new PostMethod("http://localhost:8080/httpclient/xml.jsp"); 
 
      // 设置请求的内容直接从文件中读取 
      post.setRequestBody( new FileInputStream(input));  
      if (input.length() < Integer.MAX_VALUE) 
         post.setRequestContentLength(input.length()); 
      else 
         post.setRequestContentLength(EntityEnclosingMethod.CONTENT_LENGTH_CHUNKED); 
 
      // 指定请求内容的类型 
      post.setRequestHeader( "Content-type" , "text/xml; charset=GBK" ); 
      HttpClient httpclient = new HttpClient(); 
      int result = httpclient.executeMethod(post); 
      System.out.println( "Response status code: " + result); 
      System.out.println( "Response body: " ); 
      System.out.println(post.getResponseBodyAsString());  
      post.releaseConnection();  
   } 
} 

 6. 通过HTTP上传文件


httpclient使用了单独的一个HttpMethod子类来处理文件的上传,这个类就是MultipartPostMethod,该类已经封装了文件上传的细节,我们要做的仅仅是告诉它我们要上传文件的全路径即可,下面的代码片段演示如何使用这个类。

 

MultipartPostMethod filePost = new MultipartPostMethod(targetURL); 
filePost.addParameter( "fileName" , targetFilePath); 
HttpClient client = new HttpClient(); 
 
// 由于要上传的文件可能比较大 , 因此在此设置最大的连接超时时间 
client.getHttpConnectionManager(). getParams().setConnectionTimeout(5000); 
int status = client.executeMethod(filePost); 

 上面代码中,targetFilePath即为要上传的文件所在的路径。


7. 访问启用认证的页面

我们经常会碰到这样的页面,当访问它的时候会弹出一个浏览器的对话框要求输入用户名和密码后方可,这种用户认证的方式不同于我们在前面介绍的基于表单的用户身份验证。这是HTTP的认证策略,httpclient支持三种认证方式包括:基本、摘要以及NTLM认证。其中基本认证最简单、通用但也最不安全;摘要认证是在HTTP 1.1中加入的认证方式,而NTLM则是微软公司定义的而不是通用的规范,最新版本的NTLM是比摘要认证还要安全的一种方式。

下面例子是从httpclient的CVS服务器中下载的,它简单演示如何访问一个认证保护的页面:

 

import org.apache.commons.httpclient.HttpClient; 
import org.apache.commons.httpclient.UsernamePasswordCredentials; 
import org.apache.commons.httpclient.methods.GetMethod; 
 
public class BasicAuthenticationExample {  
 
   public BasicAuthenticationExample() {  
   } 
 
   public static void main(String[] args) throws Exception { 
      HttpClient client = new HttpClient(); 
      client.getState().setCredentials( "www.verisign.com" , "realm" , new UsernamePasswordCredentials( "username" , "password" ) ); 
 
      GetMethod get = new GetMethod( "https://www.verisign.com/products/index.html" ); 
      get.setDoAuthentication( true ); 
      int status = client.executeMethod( get ); 
      System.out.println(status+ "\n" + get.getResponseBodyAsString()); 
      get.releaseConnection(); 
   } 
} 

 8. 多线程模式下使用httpclient


多线程同时访问httpclient,例如同时从一个站点上下载多个文件。对于同一个HttpConnection同一个时间只能有一个线程访问,为了保证多线程工作环境下不产生冲突,httpclient使用了一个多线程连接管理器的类:MultiThreadedHttpConnectionManager,要使用这个类很简单,只需要在构造HttpClient实例的时候传入即可,代码如下:

 

MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager(); 
 
HttpClient client = new HttpClient(connectionManager); 

 以后尽管访问client实例即可。

分享到:
评论

相关推荐

    HttpClient_学习整理.

    ### HttpClient 学习整理 #### 一、简介 `HttpClient`是Apache Jakarta Commons下的一个子项目,用于提供高效、最新及功能丰富的HTTP客户端编程工具包。对于那些希望通过HTTP协议访问网络资源的Java应用程序而言,...

    HttpClient3.1 学习整理

    HttpClient httpClient = new HttpClient(); GetMethod getMethod = new GetMethod("http://example.com"); int statusCode = httpClient.executeMethod(getMethod); if (statusCode == 200) { System.out....

    httpclient4中文API和使用

    `httpClient笔记.docx`可能是用户或教程作者整理的关于使用HttpClient的笔记或实战案例,可能包括一些常见问题的解决方案,比如处理重定向、处理cookies、上传下载文件、使用HTTPS等。 学习HttpClient时,除了API...

    JAVA核心知识点整理 全面整理.zip

    - **HTTP客户端**: 学习使用HttpURLConnection或HttpClient库发送HTTP请求并处理响应。 7. **反射机制** - **Class对象**: 理解如何获取类的信息,包括类名、方法、属性等。 - **动态代理**: 探究如何在运行时...

    最近在学习常用的Java开源项目,整理一下常用的代码.zip

    以下是对"最近在学习常用的Java开源项目,整理一下常用的代码.zip"这个压缩包中可能包含的知识点的详细解释: 1. **Maven或Gradle构建工具**:Java项目通常使用Maven或Gradle进行构建和依赖管理。通过查看项目的pom...

    基于Java的工具类学习项目.zip

    本项目是一个基于Java的工具类学习项目,旨在整理和演示各种工具类的使用方法。项目涵盖了从Excel处理、HTTP请求、JSON序列化到高性能网络框架Netty的使用等多个方面。通过本项目,开发者可以学习到如何使用这些工具...

    源码 网站交互&JSON&xml&Webservice 通过httpclient获取到JSON数据展示到ListView

    免责声明:资料部分来源于合法的互联网渠道收集和整理,部分自己学习积累成果,供大家学习参考与交流。收取的费用仅用于收集和整理资料耗费时间的酬劳。 本人尊重原创作者或出版方,资料版权归原作者或出版方所有,...

    安卓开发工具箱v2.8.5高级版.txt打包整理.zip

    "apache"可能指的是Apache开源项目,或者是使用了Apache相关的技术,例如Apache HttpClient或Apache Ant等,这些在Android开发中常见且重要。而"#资源达人分享计划#"可能是一个社区活动或者论坛的标签,表示这是由...

    安卓京东2022自动炸年兽v2.0.txt打包整理.zip

    "安卓京东2022自动炸年兽v2.0.txt打包整理.zip" 这个标题指的是一个针对安卓平台的京东应用程序,该应用可能是一个自动化工具,专为参与京东2022年的“炸年兽”活动而设计。炸年兽是京东在春节期间推出的一种互动...

    安卓点击助手v12.8绿化版.txt打包整理.zip

    描述中同样提到的是"安卓点击助手v12.8绿化版.txt打包整理.zip",这进一步确认了我们关注的是一个被整理过的文本文件集合,可能包含了关于这个绿化版应用的详细信息,如安装步骤、功能介绍、使用技巧等。 【标签...

    FaceLook项目源码整理

    "FaceLook项目源码整理"是一个专注于Java编程的开源项目,它可能包含了用于面部识别、图像处理或视觉计算的相关代码。这个项目的目的是为了让开发者能够学习、理解和应用相关的技术。从提供的文件列表来看,我们可以...

    轻松上手Java爬虫:CSDN文章抓取与整理.zip

    在本压缩包中,你将找到一个Java实现的CSDN文章抓取与整理的项目,这将是一个很好的起点来学习和实践Java爬虫技术。 首先,了解Java爬虫的基础是必不可少的。Java作为一种流行的编程语言,拥有强大的网络处理库,如...

    Java手机短信项目源码Java实用源码整理learns

    这是一份实用的源码整理,对于想要深入学习Java编程,特别是对Java在实际项目中的运用感兴趣的开发者来说,是非常有价值的参考资料。 1. **短信服务接口**:在Java项目中,通常会定义一个短信服务接口,这个接口...

    Java核心知识点整理.rar

    这份"Java核心知识点整理.rar"压缩包包含了对Java语言全面而深入的总结,对于初学者和有一定经验的开发者来说,都是宝贵的参考资料。下面,我们将详细探讨Java的核心知识点,并按照一个合理的学习路线进行阐述。 1....

    C#基类整理C#比较全的基类集合

    这个压缩包文件“C#基类整理C#比较全的基类集合”可能包含了一系列C#基础类的代码示例和解释,帮助开发者理解和运用这些类。 首先,我们来看一下C#中的几个关键基类: 1. **System.Object**:所有C#类的终极基类,...

    安卓可抖视v1.2.9免费版.txt打包整理.zip

    【标题解析】 "安卓可抖视v1.2.9免费版.txt打包...对于开发者而言,这个压缩包是一个学习和参考的宝贵资源,涵盖了实际开发中的多个方面,从编程语言到应用设计,再到商业运营,都是提升技能和了解行业趋势的重要途径。

    本人整理的一些常用的c#代码

    这个压缩包“本人整理的一些常用的c#代码”显然是一个针对初学者的学习资源集合,包含了各种实用的C#代码示例,旨在帮助新手快速掌握编程基础。 1. **基础语法**:C#的基础语法结构包括变量声明、数据类型(如int、...

    java+http+操作cookies源码整理

    这个源码整理主要关注如何在Java中使用HTTP进行Cookies的操作。以下是对这些知识点的详细解释。 首先,理解Cookies的基本概念。Cookies是由服务器端发送到客户端(浏览器)的一小段文本信息,用来存储用户的状态...

    Java常用代码整理

    Java是一种广泛使用的面向对象的编程语言,以其跨平台、高性能和丰富的类库而著名。"Java常用代码整理"这个主题涵盖了Java开发中的诸多常见技术点和...通过不断学习和实践,开发者可以更加熟练地驾驭这门强大的语言。

    s2深入.NET平台和C#编程课后、上机、指导练习答案项目案例和PPT

    学习者可以通过这个案例了解如何利用C#构建一个能够从服务器获取并显示新闻的应用,这将涉及HttpClient类的使用,XML或JSON数据的解析,以及WPF或WinForms的界面设计。 最后,"课程复习PPT"是整理了整个课程内容的...

Global site tag (gtag.js) - Google Analytics