`
zzc1684
  • 浏览: 1224121 次
  • 性别: Icon_minigender_1
  • 来自: 广州
文章分类
社区版块
存档分类
最新评论

Cookies,SSL,httpclient的多线程处理,HTTP方法

阅读更多

8、Cookies


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

  1. Netscape cookie草案,是最早的cookie规范,基于rfc2109。尽管这个规范与rc2109有较大的差别,这样做可以与一些服务器兼容。
  2. rfc2109, 是w3c发布的第一个官方cookie规范。理论上讲,所有的服务器在处理cookie(版本1)时,都要遵循此规范,正因如此,HttpClient将 其设为默认的规范。遗憾的是,这个规范太严格了,以致很多服务器不正确的实施了该规范或仍在作用Netscape规范。在这种情况下,应使用兼容规范。
  3. 兼容性规范,设计用来兼容尽可能多的服务器,即使它们并没有遵循标准规范。当解析cookie出现问题时,应考虑采用兼容性规范。


   RFC2965规范暂时没有被HttpClient支持(在以后的版本为会加上),它定义了cookie版本2,并说明了版本1cookie的不足,RFC2965有意有久取代rfc2109.
  在HttpClient中,有两种方法来指定cookie规范的使用,

  1. HttpClient client = new HttpClient();
    client.getState().setCookiePolicy(CookiePolicy.COMPATIBILITY);
    这种方法设置的规范只对当前的HttpState有效,参数可取值CookiePolicy.COMPATIBILITY,CookiePolicy.NETSCAPE_DRAFT或CookiePolicy.RFC2109。
  2. System.setProperty("apache.commons.httpclient.cookiespec", "COMPATIBILITY");
    此法指的规范,对以后每个新建立的HttpState对象都有效,参数可取值"COMPATIBILITY","NETSCAPE_DRAFT"或"RFC2109"。
      常有不能解析cookie的问题,但更换到兼容规范大都能解决。

  

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

 

  1. 用一个浏览器访问服务器,以确认服务器应答正常
  2. 如果在使代理,关掉代理试试
  3. 另找一个服务器来试试(如果运行着不同的服务器软件更好)
  4. 检查代码是否按教程中讲的思路编写
  5. 设置log级别为debug,找出问题出现的原因
  6. 打开wiretrace,来追踪客户端与服务器的通信,以确实问题出现在什么地方
  7. 用telnet或netcat手工将信息发送到服务器,适合于猜测已经找到了原因而进行试验时
  8. 将netcat以监听方式运行,用作服务器以检查httpclient如何处理应答的。
  9. 利用最新的httpclient试试,bug可能在最新的版本中修复了
  10. 向邮件列表求帮助
  11. 向bugzilla报告bug.

 

  

10、SSL


  借助Java Secure Socket Extension (JSSE),HttpClient全面支持Secure Sockets Layer (SSL)或IETF Transport Layer Security (TLS)协议上的HTTP。JSSE已经jre1.4及以后的版本中,以前的版本则需要手工安装设置,具体过程参见Sun网站或本学习笔记。
  HttpClient中使用SSL非常简单,参考下面两个例子:

HttpClient httpclient = new HttpClient();
GetMethod httpget = new GetMethod("https://www.verisign.com/");
httpclient.executeMethod(httpget);
System.out.println(httpget.getStatusLine().toString());

,如果通过需要授权的代理,则如下:

HttpClient httpclient = new HttpClient();
httpclient.getHostConfiguration().setProxy("myproxyhost", 8080);
httpclient.getState().setProxyCredentials("my-proxy-realm", " myproxyhost",
new UsernamePasswordCredentials("my-proxy-username", "my-proxy-password"));
GetMethod httpget = new GetMethod("https://www.verisign.com/");
httpclient.executeMethod(httpget);
System.out.println(httpget.getStatusLine().toString());


  在HttpClient中定制SSL的步骤如下:

  1. 提供了一个实现了 org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory接口的 socket factory。这个 socket factory负责打一个到服务器的端口,使用标准的或第三方的SSL函数库,并进行象连接握手等初始化操作。通常情况下,这个初始化操作在端口被创建时 自动进行的。
  2. 实例化一个org.apache.commons.httpclient.protocol.Protocol对象。创建这个实例时,需要一个合法的协议类型(如https),一个定制的socket factory,和一个默认的端中号(如https的443端口).
    Protocol myhttps = new Protocol("https", new MySSLSocketFactory(), 443);
    然后,这个实例可被设置为协议的处理器。
    HttpClient httpclient = new HttpClient();
    httpclient.getHostConfiguration().setHost("www.whatever.com", 443, myhttps);
    GetMethod httpget = new GetMethod("/");
    httpclient.executeMethod(httpget);
  3. 通过调用Protocol.registerProtocol方法,将此定制的实例,注册为某一特定协议的默认的处理器。由此,可以很方便地定制自己的协议类型(如myhttps)。
    Protocol.registerProtocol("myhttps",
    new Protocol("https", new MySSLSocketFactory(), 9443));
    ...
    HttpClient httpclient = new HttpClient();
    GetMethod httpget = new GetMethod("myhttps://www.whatever.com/");
    httpclient.executeMethod(httpget);
    如果想用自己定制的处理器取代https默认的处理器,只需要将其注册为"https"即可。
    Protocol.registerProtocol("https",
    new Protocol("https", new MySSLSocketFactory(), 443));
    HttpClient httpclient = new HttpClient();
    GetMethod httpget = new GetMethod("https://www.whatever.com/");
    httpclient.executeMethod(httpget);


  已知的限制和问题

  1. 持续的SSL连接在Sun的低于1.4JVM上不能工作,这是由于JVM的bug造成。
  2. 通过代理访问服务器时,非抢先认证( Non-preemptive authentication)会失败,这是由于HttpClient的设计缺陷造成的,以后的版本中会修改。


  遇到问题的处理
  很多问题,特别是在jvm低于1.4时,是由jsse的安装造成的。
  下面的代码,可作为最终的检测手段。

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.Socket;

import javax.net.ssl.SSLSocketFactory;

public class Test {

public static final String TARGET_HTTPS_SERVER = "www.verisign.com";
public static final int TARGET_HTTPS_PORT = 443;

public static void main(String[] args) throws Exception {

Socket socket = SSLSocketFactory.getDefault().
createSocket(TARGET_HTTPS_SERVER, TARGET_HTTPS_PORT);
try {
Writer out = new OutputStreamWriter(
socket.getOutputStream(), "ISO-8859-1");
out.write("GET / HTTP/1.1/r/n");
out.write("Host: " + TARGET_HTTPS_SERVER + ":" +
TARGET_HTTPS_PORT + "/r/n");
out.write("Agent: SSL-TEST/r/n");
out.write("/r/n");
out.flush();
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream(), "ISO-8859-1"));
String line = null;
while ((line = in.readLine()) != null) {
System.out.println(line);
}
} finally {
socket.close();
}
}
}


  

11、httpclient的多线程处理


  使用多线程的主要目的,是为了实现并行的下 载。在httpclient运行的过程中,每个http协议的方法,使用一个HttpConnection实例。由于连接是一种有限的资源,每个连接在某 一时刻只能供一个线程和方法使用,所以需要确保在需要时正确地分配连接。HttpClient采用了一种类似jdbc连接池的方法来管理连接,这个管理工 作由 MultiThreadedHttpConnectionManager完成。

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

此 是,client可以在多个线程中被用来执行多个方法。每次调用HttpClient.executeMethod() 方法,都会去链接管理器申请一个连接实例,申请成功这个链接实例被签出(checkout),随之在链接使用完后必须归还管理器。管理器支持两个设置:

maxConnectionsPerHost 每个主机的最大并行链接数,默认为2
maxTotalConnections 客户端总并行链接最大数,默认为20


  管理器重新利用链接时,采取早归还者先重用的方式(least recently used approach)。
  由于是使用HttpClient的程序而不是HttpClient本身来读取应答包的主体,所以HttpClient无法决定什么时间连接不再使用了,这也就要求在读完应答包的主体后必须手工显式地调用releaseConnection()来释放申请的链接。

MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
HttpClient client = new HttpClient(connectionManager);
...
// 在某个线程中。
GetMethod get = new GetMethod("http://jakarta.apache.org/");
try {
client.executeMethod(get);
// print response to stdout
System.out.println(get.getResponseBodyAsStream());
} finally {
// be sure the connection is released back to the connection
// manager
get.releaseConnection();
}

对每一个HttpClient.executeMethod须有一个method.releaseConnection()与之匹配.

12、HTTP方法

 

  HttpClient支持的HTTP方法有8种,下面分述之。

  1、Options

  HTTP方法 Options用来向服务器发送请求,希望获得针对由请求URL(request url)标志的资源在请求/应答的通信过程可以使用的功能选项。通过这个方法,客户端可以在采取具体行动之前,就可对某一资源决定采取什么动作和/或以及 一些必要条件,或者了解服务器提供的功能。这个方法最典型的应用,就是用来获取服务器支持哪些HTTP方法。
  HttpClient中有一个类叫OptionsMethod,来支持这个HTTP方法,利用这个类的getAllowedMethods方法,就可以很简单地实现上述的典型应用。

OptionsMethod options = new OptionsMethod("http://jakarta.apache.org");
// 执行方法并做相应的异常处理
...
Enumeration allowedMethods = options.getAllowedMethods();
options.releaseConnection();


  2、Get

    HTTP方法GET用来取回请求URI(request-URI)标志的任何信息(以实体(entity)的形式),"get"这个单词本意就是”获取 “的意思。如果请求URI指向的一个数据处理过程,那这个过程生成的数据,在应答中以实体的形式被返回,而不是将这个过程的代码的返回。
  如果 HTTP包中含有If-ModifiedSince, If-Unmodified-Since, If-Match, If-None-Match, 或 If-Range等头字段,则GET也就变成了”条件GET“,即只有满足上述字段描述的条件的实体才被取回,这样可以减少一些非必需的网络传输,或者减 少为获取某一资源的多次请求(如第一次检查,第二次下载)。(一般的浏览器,都有一个临时目录,用来缓存一些网页信息,当再次浏览某个页面的时候,只下载 那些修改过的内容,以加快浏览速度,就是这个道理。至于检查,则常用比GET更好的方法HEAD来实现。)如果HTTP包中含有Range头字段,那么请 求URI指定的实体中,只有决定范围条件的那部分才被取回来。(用过多线程下载工具的朋友,可能比较容易理解这一点)
  这个方法的典型应用,用 来从web服务器下载文档。HttpClient定义了一个类叫GetMethod来支持这个方法,用GetMethod类中 getResponseBody, getResponseBodyAsStream 或 getResponseBodyAsString函数就可以取到应答包包体中的文档(如HTML页面)信息。这这三个函数 中,getResponseBodyAsStream通常是最好的方法,主要是因为它可以避免在处理下载的文档之前缓存所有的下载的数据。

GetMethod get = new GetMethod("http://jakarta.apache.org");
// 执行方法,并处理失败的请求.
...
InputStream in = get.getResponseBodyAsStream();
// 利用输入流来处理信息。
get.releaseConnection();


  对GetMethod的最常见的不正确的使用,是没有将全部的应答主体的数据读出来。还有,必须注意要手工明确地将链接释放。

  3、Head

   HTTP的Head方法,与Get方法完全一致,唯一的差别是服务器不能在应答包中包含主体(message-body),而且一定不能包含主体。使用 这个方法,可以使得客户无需将资源下载回就可就以得到一些关于它的基本信息。这个方法常用来检查超链的可访问性以及资源最近有没有被修改。
  HTTP的head方法最典型的应用,是获取资源的基本信息。HttpClient定义了HeadMethod类支持这个方法,HeadMethod类与其它*Method类一样,用 getResponseHeaders()取回头部信息,而没有自己的特殊方法。

HeadMethod head = new HeadMethod("http://jakarta.apache.org");
// 执行方法,并处理失败的请求.
...
// 取回应答包的头字段信息.
Header[] headers = head.getResponseHeaders();

// 只取回最后修改日期字段的信息.
String lastModified = head.getResponseHeader("last-modified").getValue();



  4、Post

   Post在英文有“派驻”的意思,HTTP方法POST就是要求服务器接受请求包中的实体,并将其作为请求URI的下属资源。从本质上说,这意味着服务 器要保存这个实体信息,而且通常由服务器端的程序进行处理。Post方法的设计意图,是要以一种统一的方式实现下列功能:

  1. 对已有的资源做评注
  2. 将信息发布到BBS、新闻组、邮件列表,或类似的文章组中
  3. 将一块数据,提交给数据处理进程
  4. 通过追加操作,来扩展一个数据库

  这些都操作期待着在服务器端产生一定的“副作用”,如修改了数据库等。
   HttpClient定义PostMethod类以支持该HTTP方法,在httpclient中,使用post方法有两个基本的步骤:为请求包准备数 据,然后读取服务器来的应答包的信息。通过调用 setRequestBody()函数,来为请求包提供数据,它可以接收三类参数:输入流、名值对数组或字符串。至于读取应答包需要调用 getResponseBody* 那一系列的方法,与GET方法处理应答包的方法相同。
  常见问题是,没有将全部应答读取(无论它对程序是否有用),或没有释放链接资源。

分享到:
评论

相关推荐

    httpclient

    HttpClient支持多种HTTP方法,如GET、POST、PUT、DELETE等,可以方便地进行HTTP头的设置,发送cookies,处理重定向,甚至实现HTTP/1.1和HTTP/2之间的平滑切换。此外,HttpClient还提供了对HTTPS的支持,确保数据传输...

    HttpClient4.2.5

    10. **多线程支持**:HttpClient4.2.5支持多线程环境,可以并发地执行多个HTTP请求,这对于批量处理或高并发场景非常有用。 11. **性能优化**:HttpClient4.2.5版本在性能上进行了优化,例如,改进了内存管理,减少...

    HttpClient3.1.jar

    `SingleClientConnManager`是默认的实现,适用于单线程或少量并发的场景,而`MultiThreadedHttpConnectionManager`则更适合多线程环境,可以有效管理多个并发的HTTP连接。 HttpClient还支持处理HTTP状态码和响应头...

    org.apache.commons.httpclient相关资源包

    这个版本(3.0)支持HTTP/1.0和HTTP/1.1协议,包含了处理连接管理、多线程请求、SSL/TLS安全连接等功能。用户可以通过HttpClient类创建HTTP请求,设置请求头,发送数据,并获取响应。 3. **commons-logging.jar**:...

    httpclient jar包

    - 它支持多种HTTP方法,如GET、POST、PUT、DELETE等,同时支持HTTP连接管理、重定向处理、身份验证、cookies管理等功能。 2. **POST提交**: - POST方法常用于向服务器发送数据,比如提交表单或上传文件。...

    HttpClient 4.4英文版文档

    HttpClient 4.4是Apache HTTP Components项目的一部分,是一个用于发送HTTP请求并处理HTTP响应的Java客户端。文档涵盖了此版本中实现的功能和API的使用细节。 ### 1. HttpClient基础 #### 1.1 请求执行 - **HTTP...

    commons-httpclient,java中使用httpclient中使用的扩展工具

    默认实现`SingleClientConnManager`适用于单线程或短连接的应用,而`MultiThreadedHttpConnectionManager`则适合多线程和长时间运行的程序,它可以维护一个连接池,提高性能。 2. **请求构造**:你可以使用`...

    HttpClient4.5.2

    3. **执行器服务(ExecutorService)**:HttpClient 4.5.2支持使用Java的`ExecutorService`来并发执行请求,这使得在多线程环境中更高效地处理请求成为可能。 4. **SSL/TLS支持**:HttpClient支持HTTPS通信,通过...

    httpClient使用指南最新版

    - **1.2.1 HttpClient线程安全性**: `HttpClient`实例本身不是线程安全的,但在正确配置下,可以支持多线程并发访问。 - **1.2.2 HttpClient资源释放**: 使用完`HttpClient`后,应该调用其提供的方法来释放资源,...

    httpclient-4.5.3

    HttpClient还支持多线程并发请求,对于需要批量处理HTTP任务的场景,它的性能优势尤为明显。 在"使用说明.txt"中,通常会涵盖以下关键内容: 1. **初始化HttpClient**:首先,你需要创建一个HttpClient实例,这...

    HttpClient源码

    HttpClient是Apache基金会开发的一个开源HTTP客户端库,广泛用于Java开发者进行网络通信。它提供了高度可配置性和灵活性,使得...同时,这也是一个提升Java编程技能,特别是对I/O、多线程和网络协议理解的好机会。

    httpClient实用指南

    - 探讨了如何在多线程环境中高效执行HTTP请求。 ##### 2.10 连接驱逐策略 - 介绍了连接驱逐策略的作用及其配置方法。 ##### 2.11 连接保活策略 - 讨论了连接保活策略的原理和应用,以保持连接的有效性。 #### ...

    httpclient3个jar包

    - **线程安全**:HttpClient 3.x版本不完全线程安全,如果在多线程环境中使用,需要正确管理和同步HttpClient实例。 - **连接管理**:HttpClient需要管理HTTP连接,包括连接池和超时设置,以优化性能和避免资源耗尽...

    httpclient-3.1.zip

    对于多线程或长连接需求,可以使用`MultiThreadedHttpConnectionManager`。 3. **HttpRequest和HttpResponse**:分别代表HTTP请求和响应。这些对象包含了HTTP方法(GET, POST等)、头信息、实体内容等。`HttpGet`和...

    httpclient-tutorial.pdf

    - HttpClient线程安全:确保在多线程环境下HttpClient的正确使用。 - 资源释放:HttpClient实例的正确关闭和资源清理。 - HTTP执行上下文:执行请求时的上下文环境。 - HTTP协议拦截器:在HTTP请求/响应处理中进行...

    HttpClient 4.0中文教程

    - **多线程**: 支持并发执行多个请求,提高应用性能。 **2.11 连接收回策略** - **连接收回**: 为了防止资源泄露,连接管理器会定期检查空闲连接并关闭它们。 **2.12 连接保持活动的策略** - **连接保持活动**: ...

    HttpClient4.5源码

    2. **httpclient**:这是HttpClient的核心模块,实现了基本的HTTP协议功能,如GET、POST、PUT等请求方法,以及处理响应、重定向、cookies和连接管理。 3. **httpclient-cache**:这个模块提供了HTTP缓存支持,遵循...

    httpclient tutorial

    1.2.1 HttpClient线程安全:了解HttpClient对象是否可以安全地在多线程环境中使用。 1.2.2 HttpClient资源释放:了解如何释放HttpClient所占用的资源。 1.3 HTTP执行上下文:介绍如何配置和使用HTTP执行上下文,...

Global site tag (gtag.js) - Google Analytics