Terry.Li-彬

虚其心,可解天下之问;专其心,可治天下之学;静其心,可悟天下之理;恒其心,可成天下之业。

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  143 随笔 :: 344 文章 :: 130 评论 :: 0 Trackbacks
虽然用telnet这样的程序都可把页面取回来,但是在与web服务器的交互中,如果涉及或https或ssl等内容,一般功能相对完备的http客户端 还是非常必要的。IE或NetScape等浏览器确实不错,可是如果为实现持续互动而在程序调用浏览器,我个人认为其中的工作量还是不小的,这还没考虑版 权问题。最好的办法,就是能有一个开源的包,能实现http客户端的功能,供我们开发的程序调用。httpclient就是这么一个包,我相信可能有比它的实现更好的,但目前我只关注这个。:)
下面是nogoop做的功能比较表:

Features nogoop Sun JRE < 1.4.2 Sun JRE 1.4.2 Innovation Apache/Jakarta
s


X X
plug compatible X X X X [partial]
true request output stream


X X
true response input stream X

X X
connection keep alive X X X X X
connection pool throttling X


X
connection/request timeout X
X [uns] X X
idle connection timeout X


X
pipelining of requests


X
alternate DNS resolution (dnsjava) X



SSL X X X X X
basic authentication X X X X X
digest authentication X X X X X
NTLM authentication X
[Windows only]
X
proxy authentication X X X X X
minimum JRE version 1.2 1 01年4月2日 1.2 1.2
price $499 free free free free
source available X

X X
diagnostic tracing X

X X
actively supported X X X
X
fix turnaround fast slow slow none medium
license purchase Sun JRE Sun JRE LGPL Apache

1、HttpClient的功能

  1. 基于标准,纯正java,实现了http1.0和1.1。

  2. 在一个可扩展的OO框架内,实现了HTTP的全部方法(GET, POST,
    PUT, DELETE, HEAD, OPTIONS, and TRACE)

  3. 支持HTTPS(ssl上的HTTP)的加密操作

  4. 透明地穿过HTTP代理建立连接

  5. 通过CONNECT方法,利用通过建立穿过HTTP代理的HTTPS连接

  6. 利用本地Java socket,透明地穿过SOCKS(版本5和4)代理建立连接

  7. 支持利用Basic、Digest和NTLM加密的认证

  8. 支持用于上传大文件的Multi-Part表单POST方法

  9. 插件式安全socket实现,易于使用第三方的解决方案

  10. 连接管理,支持多线程应用,支持设定单个主机总连接和最高连接数量,自动检测和关闭失效连接

  11. 直接将请求信息流送到服务器的端口

  12. 直接读取从服务器的端口送出的应答信息

  13. 支持HTTP/1.0中用KeepAlive和HTTP/1.1中用persistance设置的持久连接

  14. 直接访问由服务器送出的应答代码和头部信息

  15. 可设置连接超时时间

  16. HttpMethods 实现Command Pattern,以允许并行请求或高效连接复用

  17. 遵循the Apache Software License协议,源码免费可得

2、预备工作


对jre1.3.*,如果要HttpClient支持https,则需要下载并安装jssejce.安装的步骤如下:
1)下载jsse和jce.
2)检查CLASSPATH中没有与jsse和jce相关的jar包
3)将 US_export_policy.jar、local_policy.jar、jsse.jar、jnet.jar、jce1_2_x.jar、sunjce_provider.jar、jcert.jar复制到目录:
UNIX:$JDK_HOME/jre/lib/ext
Windows:%JDK_HOME%"jre"lib"ext
4)修改下述目录下的java.security文件。
UNIX:$JDK_HOME/jre/lib/security/
Windows:%JDK_HOME%"jre"lib"security"
5)

#
# List of providers and their preference orders:
#
security.provider.1=sun.security.provider.Sun
security.provider.2=com.sun.rsajca.Provider
改为:
#
# List of providers and their preference orders:
#
security.provider.1=com.sun.crypto.provider.SunJCE
security.provider.2=sun.security.provider.Sun
security.provider.3=com.sun.rsajca.Provider
security.provider.4=com.sun.net.ssl.internal.ssl.Provider

HttpClient还要求安装commons-logging,下面跟httpclient一块安装。

3、取得源码

cvs -d :pserver:anoncvs@cvs.apache.org:/home/cvspublic login
password: anoncvs
cvs -d :pserver:anoncvs@cvs.apache.org:/home/cvspublic checkout jakarta-commons/logging
cvs -d :pserver:anoncvs@cvs.apache.org:/home/cvspublic checkout jakarta-commons/httpclient

编译:
cd jakarta-commons/logging
ant dist
cp dis/*.jar ../httpclient/lib/
cd ../httpclient
ant dist

4、使用HttpClient编程的基本步聚

  1. 创建 HttpClient 的一个实例.

  2. 创建某个方法(DeleteMethod,EntityEnclosingMethod,ExpectContinueMethod, GetMethod,HeadMethod,MultipartPostMethod,OptionsMethod,PostMethod, PutMethod,TraceMethod)的一个实例,一般可用要目标URL为参数。

  3. 让 HttpClient 执行这个方法.

  4. 读取应答信息.

  5. 释放连接.

  6. 处理应答.

在执行方法的过程中,有两种异常,一种是HttpRecoverableException,表示偶然性错误发生,一般再试可能成功,另一种是IOException,严重错误。
这儿有这个教程中的一个例程,可以下载

5、认证


HttpClient三种不同的认证方案: Basic, Digest and NTLM. 这些方案可用于服务器或代理对客户端的认证,简称服务器认证或代理认证。
1)服务器认证(Server Authentication)
HttpClient处理服务器认证几乎是透明的,仅需要开发人员提供登录信息(login credentials)。登录信息保存在HttpState类的实例中,可以通过 setCredentials(String realm, Credentials cred)和getCredentials(String realm)来获取或设置。注意,设定对非特定站点访问所需要的登录信息,将realm参数置为null. HttpClient内建的自动认证,可以通过HttpMethod类的setDoAuthentication(boolean doAuthentication)方法关闭,而且这次关闭只影响HttpMethod当前的实例。
抢先认证(Preemptive Authentication)可以通过下述方法打开.
client.getState().setAuthenticationPreemptive(true);
在这种模式时,HttpClient会主动将basic认证应答信息传给服务器,即使在某种情况下服务器可能返回认证失败的应答,这样做主要是为了减少连接的建立。为使每个新建的 HttpState实例都实行抢先认证,可以如下设置系统属性。
setSystemProperty(Authenticator.PREEMPTIVE_PROPERTY, "true");

Httpclient实现的抢先认证遵循rfc2617.
2)代理认证(proxy authentication)
除了登录信息需单独存放以外,代理认证与服务器认证几乎一致。用 setProxyCredentials(String realm, Credentials cred)和 getProxyCredentials(String realm)设、取登录信息。
3)认证方案(authentication schemes)
Basic
是HTTP中规定最早的也是最兼容(?)的方案,遗憾的是也是最不安全的一个方案,因为它以明码传送用户名和密码。它要求一个UsernamePasswordCredentials实例,可以指定服务器端的访问空间或采用默认的登录信息。
Digest
是在HTTP1.1中增加的一个方案,虽然不如Basic得到的软件支持多,但还是有广泛的使用。Digest方案比Basic方案安全得多,因它根本 就不通过网络传送实际的密码,传送的是利用这个密码对从服务器传来的一个随机数(nonce)的加密串。它要求一个 UsernamePasswordCredentials实例,可以指定服务器端的访问空间或采用默认的登录信息。
NTLM
这是 HttpClient支持的最复杂的认证协议。它M$设计的一个私有协议,没有公开的规范说明。一开始由于设计的缺陷,NTLM的安全性比Digest 差,后来经过一个ServicePack补丁后,安全性则比较Digest高。NTLM需要一个NTCredentials实例. 注意,由于NTLM不使用访问空间(realms)的概念,HttpClient利用服务器的域名作访问空间的名字。还需要注意,提供给 NTCredentials的用户名,不要用域名的前缀 - 如: "adrian" 是正确的,而 "DOMAIN"adrian" 则是错的.
NTLM认证的工作机制与basic和digest有很大的差别。这些差别一般由HttpClient处理,但理解这些差别有助避免在使用NTLM认证时出现错误。

  1. 从HttpClientAPI的角度来看,NTLM与其它认证方式一样的工作,差别是需要提供'NTCredentials'实例而不是'UsernamePasswordCredentials'(其实,前者只是扩展了后者)

  2. 对NTLM认证,访问空间是连接到的机器的域名,这对多域名主机会有一些麻烦.只有HttpClient连接中指定的域名才是认证用的域名。建议将realm设为null以使用默认的设置。

  3. NTLM只是认证了一个连接而不是一请求,所以每当一个新的连接建立就要进行一次认证,且在认证的过程中保持连接是非常重要的。 因此,NTLM不能同时用于代理认证和服务器认证,也不能用于http1.0连接或服务器不支持持久连接的情况。

6、重定向


由于技术限制,以及为保证2.0发布版API的稳定,HttpClient还不能自动处重定向,但对重定向到同一主机、同一端口且采用同一协议的情况HttpClient可以支持。不能自动的处理的情况,包括需要人工交互的情况,或超出httpclient的能力。
当服务器重定向指令指到不同的主机时,HttpClient只是简单地将重定向状态码作为应答状态。所有的300到399(包含两端)的返回码,都表示是重定向应答。常见的有:

  1. 301 永久移动. HttpStatus.SC_MOVED_PERMANENTLY

  2. 302 临时移动. HttpStatus.SC_MOVED_TEMPORARILY

  3. 303 See Other. HttpStatus.SC_SEE_OTHER

  4. 307 临时重定向. HttpStatus.SC_TEMPORARY_REDIRECT

当收到简单的重定向时,程序应从HttpMethod对象中抽取新的URL并将其下载。另外,限制一下重定向次数是个好的主意,这可以避免递归循环。新的URL可以从头字段Location中抽取,如下:
String redirectLocation;
Header locationHeader = method.getResponseHeader("location");
if (locationHeader != null) {
redirectLocation = locationHeader.get();
} else {
// The response is invalid and did not provide the new location for
// the resource. Report an error or possibly handle the response
// like a 404 Not Found error.
}

特殊重定向:

  1. 300 多重选择. HttpStatus.SC_MULTIPLE_CHOICES

  2. 304 没有改动. HttpStatus.SC_NO T_MODIFIED

  3. 305 使用代理. HttpStatus.SC_USE_PROXY

7、字符编码(character encoding)


一个HTTP协议的请求或应答的头部(在http协议中,数据包分 为两部分,一部分是头部,由一些名值对构成,一部分是主体(body),是真正传办理的数据(如HTML页面等)),必须以US-ASCII编码,这是因 为头部不传数据而只描述被要传输的数据的一些信息,一个例外是,它是数据但是通过头部进行传输的,所以它也要用US-ASCII编码。
HTTP数据包的主体部分,可以用任何一种方式进行编码,默认是ISO-8859-1,具体可以用头部字段Content-Type指定。可以利用 addRequestHeader方法,设定编码方式;用 getResponseCharSet取得编码方式。对HTML或XML等类型的文档,它们的本身的Content-Type也可以指定编码方式,主要区 分两者的作用范围以得到正确实的解码。
URL的编码标准,由RFC1738指定为,只能是由可打印8位/字节的us-ascii字符组成,80-ff不是us-ascii字符,而00-1F是控制字符,这两个区域中用的字符都须加以编码(encoded)。

8、s


HttpClient能自动管理,包括允许服务器设置并在需要的时候自动将返回服务器,它也支持手工设置后发送到服务器端。不幸的是,对如何处理,有几个 规范互相冲突:Netscape 草案, RFC2109, RFC2965,而且还有很大数量的软件商的实现不遵循任何规范. 为了处理这种状况,HttpClient提供了策略驱动的管理方式。HttpClient支持的规范有:
  1. Netscape 草案,是最早的规范,基于rfc2109。尽管这个规范与rc2109有较大的差别,这样做可以与一些服务器兼容。

  2. rfc2109, 是w3c发布的第一个官方规范。理论上讲,所有的服务器在处理(版本1)时,都要遵循此规范,正因如此,HttpClient将其设为默认的规范。遗憾的 是,这个规范太严格了,以致很多服务器不正确的实施了该规范或仍在作用Netscape规范。在这种情况下,应使用兼容规范。

  3. 兼容性规范,设计用来兼容尽可能多的服务器,即使它们并没有遵循标准规范。当解析出现问题时,应考虑采用兼容性规范。

RFC2965规范暂时没有被HttpClient支持(在以后的版本为会加上),它定义了版本2,并说明了版本1的不足,RFC2965有意有久取代rfc2109.
在HttpClient中,有两种方法来指定规范的使用,
  1. HttpClient client = new HttpClient();
    client.getState().setPolicy(Policy.COMPATIBILITY);
    这种方法设置的规范只对当前的HttpState有效,参数可取值Policy.COMPATIBILITY,Policy.NETSCAPE_DRAFT或Policy.RFC2109。

  2. System.setProperty("apache.commons.httpclient.spec", "COMPATIBILITY");
    此法指的规范,对以后每个新建立的HttpState对象都有效,参数可取值"COMPATIBILITY","NETSCAPE_DRAFT"或"RFC2109"。
    常有不能解析的问题,但更换到兼容规范大都能解决。

9、使用HttpClient遇到问题怎么办?

  1. 用一个浏览器访问服务器,以确认服务器应答正常

  2. 如果在使代理,关掉代理试试

  3. 另找一个服务器来试试(如果运行着不同的服务器软件更好)

  4. 检查代码是否按教程中讲的思路编写

  5. 设置log级别为debug,找出问题出现的原因

  6. 打开wiretrace,来追踪客户端与服务器的通信,以确实问题出现在什么地方

  7. 用telnet或netcat手工将信息发送到服务器,适合于猜测已经找到了原因而进行试验时

  8. 将netcat以监听方式运行,用作服务器以检查httpclient如何处理应答的。

  9. 利用最新的httpclient试试,bug可能在最新的版本中修复了

  10. 向邮件列表求帮助

  11. 向bugzilla报告bug.
posted on 2008-02-13 22:23 礼物 阅读(883) 评论(0)  编辑  收藏 所属分类: Jakarta