﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-小菜毛毛技术分享-随笔分类-httpclient</title><link>http://www.blogjava.net/caizh2009/category/44583.html</link><description>与大家共同成长</description><language>zh-cn</language><lastBuildDate>Fri, 09 Apr 2010 07:06:53 GMT</lastBuildDate><pubDate>Fri, 09 Apr 2010 07:06:53 GMT</pubDate><ttl>60</ttl><item><title>HttpClient入门</title><link>http://www.blogjava.net/caizh2009/archive/2010/04/09/317846.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Fri, 09 Apr 2010 06:38:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/archive/2010/04/09/317846.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/317846.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/archive/2010/04/09/317846.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/317846.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/317846.html</trackback:ping><description><![CDATA[<blockquote>HttpClient 是 Apache Jakarta Common
下的子项目，可以用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包，并且它支持 HTTP
协议最新的版本和建议。本文首先介绍 HTTPClient，然后根据作者实际工作经验给出了一些常见问题的解决方法。</blockquote>
<p><a name="N1004B">HttpClient简介</a></p>
<p>HTTP 协议可能是现在 Internet 上使用得最多、最重要的协议了，越来越多的 Java 应用程序需要直接通过 HTTP
协议来访问网络资源。虽然在 JDK 的 java.net 包中已经提供了访问 HTTP 协议的基本功能，但是对于大部分应用程序来说，JDK
库本身提供的功能还不够丰富和灵活。HttpClient 是 Apache Jakarta Common
下的子项目，用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包，并且它支持 HTTP
协议最新的版本和建议。HttpClient 已经应用在很多的项目中，比如 Apache Jakarta 上很著名的另外两个开源项目 Cactus
和 HTMLUnit 都使用了 HttpClient，更多使用 HttpClient 的应用可以参见<a href="http://wiki.apache.org/jakarta-httpclient/HttpClientPowered">http://wiki.apache.org/jakarta-httpclient/HttpClientPowered</a>。HttpClient
项目非常活跃，使用的人还是非常多的。目前 HttpClient 版本是在 2005.10.11 发布的 3.0 RC4 。</p>
<br />
<table border="0" cellpadding="0" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" /><br />
            <img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" /></td>
        </tr>
    </tbody>
</table>
<table align="right" cellpadding="0" cellspacing="0">
    <tbody>
        <tr align="right">
            <td><img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" /><br />
            <table border="0" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16" /><br />
                        </td>
                        <td align="right" valign="top"><a href="http://www.ibm.com/developerworks/cn/opensource/os-httpclient/#main" class="fbox"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p><a name="N10058">HttpClient 功能介绍</a></p>
<p>以下列出的是 HttpClient 提供的主要的功能，要知道更多详细的功能可以参见 HttpClient 的主页。</p>
<ul>
    <li>实现了所有 HTTP 的方法（GET,POST,PUT,HEAD 等）</li>
    <li>支持自动转向</li>
    <li>支持 HTTPS 协议</li>
    <li>支持代理服务器等</li>
</ul>
<p>下面将逐一介绍怎样使用这些功能。首先，我们必须安装好 HttpClient。</p>
<ul>
    <li>HttpClient 可以在<a href="http://jakarta.apache.org/commons/httpclient/downloads.html">http://jakarta.apache.org/commons/httpclient/downloads.html</a>下
    载</li>
    <li>HttpClient 用到了 Apache Jakarta common 下的子项目 logging，你可以从这个地址<a href="http://jakarta.apache.org/site/downloads/downloads_commons-logging.cgi">http://jakarta.apache.org/site/downloads/downloads_commons-logging.cgi</a>下
    载到 common logging，从下载后的压缩包中取出 commons-logging.jar 加到 CLASSPATH 中</li>
    <li>HttpClient 用到了 Apache Jakarta common 下的子项目 codec，你可以从这个地址<a href="http://jakarta.apache.org/site/downloads/downloads_commons-codec">http://jakarta.apache.org/site/downloads/downloads_commons-codec</a>.cgi
    下载到最新的 common codec，从下载后的压缩包中取出 commons-codec-1.x.jar 加到 CLASSPATH 中</li>
</ul>
<br />
<table border="0" cellpadding="0" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" /><br />
            <img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" /></td>
        </tr>
    </tbody>
</table>
<table align="right" cellpadding="0" cellspacing="0">
    <tbody>
        <tr align="right">
            <td><img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" /><br />
            <table border="0" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16" /><br />
                        </td>
                        <td align="right" valign="top"><a href="http://www.ibm.com/developerworks/cn/opensource/os-httpclient/#main" class="fbox"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p><a name="N1008B">HttpClient 基本功能的使用</a></p>
<p><a name="N10091">GET 方法</a></p>
<p>使用 HttpClient 需要以下 6 个步骤：</p>
<p>1.	创建 HttpClient 的实例</p>
<p>2.	创建某种连接方法的实例，在这里是 GetMethod。在 GetMethod 的构造函数中传入待连接的地址</p>
<p>3.	调用第一步中创建好的实例的 execute 方法来执行第二步中创建好的 method 实例</p>
<p>4.	读 response</p>
<p>5.	释放连接。无论执行方法是否成功，都必须释放连接</p>
<p>6.	对得到后的内容进行处理</p>
<p>根据以上步骤，我们来编写用GET方法来取得某网页内容的代码。</p>
<ul>
    <li>大部分情况下 HttpClient 默认的构造函数已经足够使用。
    <table border="0" cellpadding="0" cellspacing="0" width="100%">
        <tbody>
            <tr>
                <td>
                <pre>HttpClient httpClient = new HttpClient();<br />
                <br />
                </pre>
                </td>
            </tr>
        </tbody>
    </table>
    <br />
    </li>
    <li>创建GET方法的实例。在GET方法的构造函数中传入待连接的地址即可。用GetMethod将会自动处理转发过程，如果想要把自动处理
    转发过程去掉的话，可以调用方法setFollowRedirects(false)。
    <table border="0" cellpadding="0" cellspacing="0" width="100%">
        <tbody>
            <tr>
                <td>
                <pre>GetMethod getMethod = new GetMethod("http://www.ibm.com/");<br />
                <br />
                </pre>
                </td>
            </tr>
        </tbody>
    </table>
    <br />
    </li>
    <li>调用实例httpClient的executeMethod方法来执行getMethod。由于是执行在网络上的程序，在运行
    executeMethod方法的时候，需要处理两个异常，分别是HttpException和IOException。引起第一种异常的原因主要可能是
    在构造getMethod的时候传入的协议不对，比如不小心将"http"写成"htp"，或者服务器端返回的内容不正常等，并且该异常发生是不可恢复
    的；第二种异常一般是由于网络原因引起的异常，对于这种异常
    （IOException），HttpClient会根据你指定的恢复策略自动试着重新执行executeMethod方法。HttpClient的恢复
    策略可以自定义（通过实现接口HttpMethodRetryHandler来实现）。通过httpClient的方法setParameter设置你实
    现的恢复策略，本文中使用的是系统提供的默认恢复策略，该策略在碰到第二类异常的时候将自动重试3次。executeMethod返回值是一个整数，表示
    了执行该方法后服务器返回的状态码，该状态码能表示出该方法执行是否成功、需要认证或者页面发生了跳转（默认状态下GetMethod的实例是自动处理跳
    转的）等。
    <table border="0" cellpadding="0" cellspacing="0" width="100%">
        <tbody>
            <tr>
                <td>
                <pre>//设置成了默认的恢复策略，在发生异常时候将自动重试3次，在这里你也可以设置成自定义的恢复策略<br />
                <br />
                getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, <br />
                <br />
                new DefaultHttpMethodRetryHandler()); <br />
                <br />
                //执行getMethod<br />
                <br />
                int statusCode = client.executeMethod(getMethod);<br />
                <br />
                if (statusCode != HttpStatus.SC_OK) {<br />
                <br />
                System.err.println("Method failed: " + getMethod.getStatusLine());<br />
                <br />
                }<br />
                <br />
                </pre>
                </td>
            </tr>
        </tbody>
    </table>
    <br />
    </li>
    <li>
    在返回的状态码正确后，即可取得内容。取得目标地址的内容有三种方法：第一种，getResponseBody，该方法返回的是目标的二进制的byte
    流；第二种，getResponseBodyAsString，这个方法返回的是String类型，值得注意的是该方法返回的String的编码是根据系
    统默认的编码方式，所以返回的String值可能编码类型有误，在本文的"字符编码"部分中将对此做详细介绍；第三
    种，getResponseBodyAsStream，这个方法对于目标地址中有大量数据需要传输是最佳的。在这里我们使用了最简单的
    getResponseBody方法。
    <table border="0" cellpadding="0" cellspacing="0" width="100%">
        <tbody>
            <tr>
                <td>
                <pre>byte[] responseBody = method.getResponseBody();<br />
                <br />
                </pre>
                </td>
            </tr>
        </tbody>
    </table>
    <br />
    </li>
    <li>释放连接。无论执行方法是否成功，都必须释放连接。
    <table border="0" cellpadding="0" cellspacing="0" width="100%">
        <tbody>
            <tr>
                <td>
                <pre>method.releaseConnection();<br />
                <br />
                </pre>
                </td>
            </tr>
        </tbody>
    </table>
    <br />
    </li>
    <li>处理内容。在这一步中根据你的需要处理内容，在例子中只是简单的将内容打印到控制台。
    <table border="0" cellpadding="0" cellspacing="0" width="100%">
        <tbody>
            <tr>
                <td>
                <pre>System.out.println(new String(responseBody));<br />
                <br />
                </pre>
                </td>
            </tr>
        </tbody>
    </table>
    <br />
    </li>
</ul>
<p>下面是程序的完整代码，这些代码也可在附件中的test.GetSample中找到。</p>
<br />
<table border="0" cellpadding="0" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td>
            <pre>package test;<br />
            <br />
            import java.io.IOException;<br />
            <br />
            import org.apache.commons.httpclient.*;<br />
            <br />
            import org.apache.commons.httpclient.methods.GetMethod;<br />
            <br />
            import org.apache.commons.httpclient.params.HttpMethodParams;<br />
            <br />
            public class GetSample{<br />
            <br />
            public static void main(String[] args) {<br />
            <br />
            //构造HttpClient的实例<br />
            <br />
            HttpClient httpClient = new HttpClient();<br />
            <br />
            //创建GET方法的实例<br />
            <br />
            GetMethod getMethod = new GetMethod("http://www.ibm.com");<br />
            <br />
            //使用系统提供的默认的恢复策略<br />
            <br />
            getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,<br />
            <br />
            new DefaultHttpMethodRetryHandler());<br />
            <br />
            try {<br />
            <br />
            //执行getMethod<br />
            <br />
            int statusCode = httpClient.executeMethod(getMethod);<br />
            <br />
            if (statusCode != HttpStatus.SC_OK) {<br />
            <br />
            System.err.println("Method failed: "<br />
            <br />
            + getMethod.getStatusLine());<br />
            <br />
            }<br />
            <br />
            //读取内容 <br />
            <br />
            byte[] responseBody = getMethod.getResponseBody();<br />
            <br />
            //处理内容<br />
            <br />
            System.out.println(new String(responseBody));<br />
            <br />
            } catch (HttpException e) {<br />
            <br />
            //发生致命的异常，可能是协议不对或者返回的内容有问题<br />
            <br />
            System.out.println("Please check your provided http address!");<br />
            <br />
            e.printStackTrace();<br />
            <br />
            } catch (IOException e) {<br />
            <br />
            //发生网络异常<br />
            <br />
            e.printStackTrace();<br />
            <br />
            } finally {<br />
            <br />
            //释放连接<br />
            <br />
            getMethod.releaseConnection();<br />
            <br />
            }<br />
            <br />
            }<br />
            <br />
            }<br />
            <br />
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p><a name="N100E8">POST方法</a></p>
<p>根据RFC2616，对POST的解释如下：POST方法用来向目的服务器发出请求，要求它接受被附在请求后的实体，并把它当作请求队列
（Request-Line）中请求URI所指定资源的附加新子项。POST被设计成用统一的方法实现下列功能：</p>
<ul>
    <li>对现有资源的注释（Annotation of existing resources）</li>
    <li>向电子公告栏、新闻组，邮件列表或类似讨论组发送消息</li>
    <li>提交数据块，如将表单的结果提交给数据处理过程</li>
    <li>通过附加操作来扩展数据库</li>
</ul>
<p>调用HttpClient中的PostMethod与GetMethod类似，除了设置PostMethod的实例与GetMethod有些
不同之外，剩下的步骤都差不多。在下面的例子中，省去了与GetMethod相同的步骤，只说明与上面不同的地方，并以登录清华大学BBS为例子进行说
明。</p>
<ul>
    <li>构造PostMethod之前的步骤都相同，与GetMethod一样，构造PostMethod也需要一个URI参数，在本例中，登录
    的地址是http://www.newsmth.net/bbslogin2.php。在创建了PostMethod的实例之后，需要给method实例
    填充表单的值，在BBS的登录表单中需要有两个域，第一个是用户名（域名叫id），第二个是密码（域名叫passwd）。表单中的域用类
    NameValuePair来表示，该类的构造函数第一个参数是域名，第二参数是该域的值；将表单所有的值设置到PostMethod中用方法
    setRequestBody。另外由于BBS登录成功后会转向另外一个页面，但是HttpClient对于要求接受后继服务的请求，比如POST和
    PUT，不支持自动转发，因此需要自己对页面转向做处理。具体的页面转向处理请参见下面的"自动转向"部分。代码如下：
    <table border="0" cellpadding="0" cellspacing="0" width="100%">
        <tbody>
            <tr>
                <td>
                <pre>String url = "http://www.newsmth.net/bbslogin2.php";<br />
                <br />
                PostMethod postMethod = new PostMethod(url);<br />
                <br />
                // 填入各个表单域的值<br />
                <br />
                NameValuePair[] data = { new NameValuePair("id", "youUserName"),				<br />
                <br />
                new NameValuePair("passwd", "yourPwd") };<br />
                <br />
                // 将表单的值放入postMethod中<br />
                <br />
                postMethod.setRequestBody(data);<br />
                <br />
                // 执行postMethod<br />
                <br />
                int statusCode = httpClient.executeMethod(postMethod);<br />
                <br />
                // HttpClient对于要求接受后继服务的请求，象POST和PUT等不能自动处理转发<br />
                <br />
                // 301或者302<br />
                <br />
                if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY || <br />
                <br />
                statusCode == HttpStatus.SC_MOVED_TEMPORARILY) {<br />
                <br />
                // 从头中取出转向的地址<br />
                <br />
                Header locationHeader = postMethod.getResponseHeader("location");<br />
                <br />
                String location = null;<br />
                <br />
                if (locationHeader != null) {<br />
                <br />
                location = locationHeader.getValue();<br />
                <br />
                System.out.println("The page was redirected to:" + location);<br />
                <br />
                } else {<br />
                <br />
                System.err.println("Location field value is null.");<br />
                <br />
                }<br />
                <br />
                return;<br />
                <br />
                }<br />
                <br />
                </pre>
                </td>
            </tr>
        </tbody>
    </table>
    <br />
    </li>
</ul>
<p>完整的程序代码请参见附件中的test.PostSample</p>
<br />
<table border="0" cellpadding="0" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" /><br />
            <img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" /></td>
        </tr>
    </tbody>
</table>
<table align="right" cellpadding="0" cellspacing="0">
    <tbody>
        <tr align="right">
            <td><img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" /><br />
            <table border="0" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16" /><br />
                        </td>
                        <td align="right" valign="top"><a href="http://www.ibm.com/developerworks/cn/opensource/os-httpclient/#main" class="fbox"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p><a name="N10110">使用HttpClient过程中常见的一些问题</a></p>
<p>下面介绍在使用HttpClient过程中常见的一些问题。</p>
<p><a name="N10119">字符编码</a></p>
<p>某目标页的编码可能出现在两个地方，第一个地方是服务器返回的http头中，另外一个地方是得到的html/xml页面中。</p>
<ul>
    <li>在http头的Content-Type字段可能会包含字符编码信息。例如可能返回的头会包含这样子的信息：Content-Type:
    text/html;
    charset=UTF-8。这个头信息表明该页的编码是UTF-8，但是服务器返回的头信息未必与内容能匹配上。比如对于一些双字节语言国家，可能服务
    器返回的编码类型是UTF-8，但真正的内容却不是UTF-8编码的，因此需要在另外的地方去得到页面的编码信息；但是如果服务器返回的编码不是UTF-
    8，而是具体的一些编码，比如gb2312等，那服务器返回的可能是正确的编码信息。通过method对象的getResponseCharSet()方
    法就可以得到http头中的编码信息。</li>
    <li>对于象xml或者html这样的文件，允许作者在页面中直接指定编码类型。比如在html中会有&lt;meta
    http-equiv="Content-Type" content="text/html;
    charset=gb2312"/&gt;这样的标签；或者在xml中会有&lt;?xml version="1.0"
    encoding="gb2312"?&gt;这样的标签，在这些情况下，可能与http头中返回的编码信息冲突，需要用户自己判断到底那种编码类型应该
    是真正的编码。</li>
</ul>
<p><a name="N1012B">自动转向</a></p>
<p>根据RFC2616中对自动转向的定义，主要有两种：301和302。301表示永久的移走（Moved
Permanently），当返回的是301，则表示请求的资源已经被移到一个固定的新地方，任何向该地址发起请求都会被转到新的地址上。302表示暂时
的转向，比如在服务器端的servlet程序调用了sendRedirect方法，则在客户端就会得到一个302的代码，这时服务器返回的头信息中
location的值就是sendRedirect转向的目标地址。</p>
<p>HttpClient支持自动转向处理，但是象POST和PUT方式这种要求接受后继服务的请求方式，暂时不支持自动转向，因此如果碰到
POST方式提交后返回的是301或者302的话需要自己处理。就像刚才在POSTMethod中举的例子：如果想进入登录BBS后的页面，必须重新发起
登录的请求，请求的地址可以在头字段location中得到。不过需要注意的是，有时候location返回的可能是相对路径，因此需要对
location返回的值做一些处理才可以发起向新地址的请求。</p>
<p>另外除了在头中包含的信息可能使页面发生重定向外，在页面中也有可能会发生页面的重定向。引起页面自动转发的标签是：&lt;meta
http-equiv="refresh" content="5;
url=http://www.ibm.com/us"&gt;。如果你想在程序中也处理这种情况的话得自己分析页面来实现转向。需要注意的是，在上面那
个标签中url的值也可以是一个相对地址，如果是这样的话，需要对它做一些处理后才可以转发。</p>
<p><a name="N1013A">处理HTTPS协议</a></p>
<p>HttpClient提供了对SSL的支持，在使用SSL之前必须安装JSSE。在Sun提供的1.4以后的版本中，JSSE已经集成到
JDK中，如果你使用的是JDK1.4以前的版本则必须安装JSSE。JSSE不同的厂家有不同的实现。下面介绍怎么使用HttpClient来打开
Https连接。这里有两种方法可以打开https连接，第一种就是得到服务器颁发的证书，然后导入到本地的keystore中；另外一种办法就是通过扩
展HttpClient的类来实现自动接受证书。</p>
<p>方法1，取得证书，并导入本地的keystore：</p>
<ul>
    <li>安装JSSE
    （如果你使用的JDK版本是1.4或者1.4以上就可以跳过这一步）。本文以IBM的JSSE为例子说明。先到IBM网站上下载JSSE的安装包。然后解
    压开之后将ibmjsse.jar包拷贝到&lt;java-home&gt;"lib"ext"目录下。</li>
    <li>取得并且导入证书。证书可以通过IE来获得：
    <p>1．	用IE打开需要连接的https网址，会弹出如下对话框：</p>
    <br />
    <img alt="" src="http://www.ibm.com/developerworks/cn/opensource/os-httpclient/images/image001.png" border="0" height="301" width="384" />
    <br />
    <p>2．	单击"View Certificate"，在弹出的对话框中选择"Details"，然后再单击"Copy to
    File"，根据提供的向导生成待访问网页的证书文件</p>
    <br />
    <img alt="" src="http://www.ibm.com/developerworks/cn/opensource/os-httpclient/images/image003.png" border="0" height="476" width="409" />
    <br />
    <p>3．	向导第一步，欢迎界面，直接单击"Next"，</p>
    <br />
    <img alt="" src="http://www.ibm.com/developerworks/cn/opensource/os-httpclient/images/image005.png" border="0" height="386" width="503" />
    <br />
    <p>4．	向导第二步，选择导出的文件格式，默认，单击"Next"，</p>
    <br />
    <img alt="" src="http://www.ibm.com/developerworks/cn/opensource/os-httpclient/images/image007.png" border="0" height="386" width="503" />
    <br />
    <p>5．	向导第三步，输入导出的文件名，输入后，单击"Next"，</p>
    <br />
    <img alt="" src="http://www.ibm.com/developerworks/cn/opensource/os-httpclient/images/image009.png" border="0" height="454" width="506" />
    <br />
    <p>6．	向导第四步，单击"Finish"，完成向导</p>
    <br />
    <img alt="" src="http://www.ibm.com/developerworks/cn/opensource/os-httpclient/images/image011.png" border="0" height="386" width="503" />
    <br />
    <p>7．	最后弹出一个对话框，显示导出成功</p>
    <br />
    <img alt="" src="http://www.ibm.com/developerworks/cn/opensource/os-httpclient/images/image013.png" border="0" height="100" width="183" />
    <br />
    </li>
    <li>
    <p>用keytool工具把刚才导出的证书倒入本地keystore。Keytool命令在&lt;java-home&gt;"bin
    "下，打开命令行窗口，并到&lt;java-home&gt;"lib"security"目录下，运行下面的命令：</p>
    <table border="0" cellpadding="0" cellspacing="0" width="100%">
        <tbody>
            <tr>
                <td>
                <pre>keytool -import -noprompt -keystore cacerts -storepass changeit -alias yourEntry1 -file your.cer<br />
                <br />
                </pre>
                </td>
            </tr>
        </tbody>
    </table>
    <br />
    <p>其中参数alias后跟的值是当前证书在keystore中的唯一标识符，但是大小写不区分；参数file后跟的是刚才通过IE导出的证
    书所在的路径和文件名；如果你想删除刚才导入到keystore的证书，可以用命令：</p>
    <table border="0" cellpadding="0" cellspacing="0" width="100%">
        <tbody>
            <tr>
                <td>
                <pre>keytool -delete -keystore cacerts -storepass changeit -alias yourEntry1<br />
                <br />
                </pre>
                </td>
            </tr>
        </tbody>
    </table>
    <br />
    </li>
    <li>写程序访问https地址。如果想测试是否能连上https，只需要稍改一下GetSample例子，把请求的目标变成一个https地
    址。
    <table border="0" cellpadding="0" cellspacing="0" width="100%">
        <tbody>
            <tr>
                <td>
                <pre>GetMethod getMethod = new GetMethod("https://www.yourdomain.com");<br />
                <br />
                </pre>
                </td>
            </tr>
        </tbody>
    </table>
    <br />
    <p>运行该程序可能出现的问题：</p>
    <p>1.	抛出异常java.net.SocketException: Algorithm SSL not
    available。出现这个异常可能是因为没有加JSSEProvider，如果用的是IBM的JSSE Provider，在程序中加入这样的一行：</p>
    <table border="0" cellpadding="0" cellspacing="0" width="100%">
        <tbody>
            <tr>
                <td>
                <pre> if(Security.getProvider("com.ibm.jsse.IBMJSSEProvider") == null)<br />
                <br />
                Security.addProvider(new IBMJSSEProvider());<br />
                <br />
                </pre>
                </td>
            </tr>
        </tbody>
    </table>
    <br />
    <p>或者也可以打开&lt;java-home&gt;"lib"security"java.security，在行</p>
    <table border="0" cellpadding="0" cellspacing="0" width="100%">
        <tbody>
            <tr>
                <td>
                <pre>security.provider.1=sun.security.provider.Sun<br />
                <br />
                security.provider.2=com.ibm.crypto.provider.IBMJCE<br />
                <br />
                </pre>
                </td>
            </tr>
        </tbody>
    </table>
    <br />
    <p>后面加入security.provider.3=com.ibm.jsse.IBMJSSEProvider</p>
    <p>2.	抛出异常java.net.SocketException: SSL implementation not
    available。出现这个异常可能是你没有把ibmjsse.jar拷贝到&lt;java-home&gt;"lib"ext"目录下。</p>
    <p>3.	抛出异常javax.net.ssl.SSLHandshakeException: unknown
    certificate。出现这个异常表明你的JSSE应该已经安装正确，但是可能因为你没有把证书导入到当前运行JRE的keystore中，请按照前
    面介绍的步骤来导入你的证书。</p>
    </li>
</ul>
<p>方法２，扩展HttpClient类实现自动接受证书</p>
<p>因为这种方法自动接收所有证书，因此存在一定的安全问题，所以在使用这种方法前请仔细考虑您的系统的安全需求。具体的步骤如下：</p>
<ul>
    <li>提供一个自定义的socket
    factory（test.MySecureProtocolSocketFactory）。这个自定义的类必须实现接口
    org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory，在实现接口
    的类中调用自定义的X509TrustManager(test.MyX509TrustManager)，这两个类可以在随本文带的附件中得到</li>
    <li>创建一个org.apache.commons.httpclient.protocol.Protocol的实例，指定协议名称和默认
    的端口号
    <table border="0" cellpadding="0" cellspacing="0" width="100%">
        <tbody>
            <tr>
                <td>
                <pre>Protocol myhttps = new Protocol("https", new MySecureProtocolSocketFactory (), 443);<br />
                <br />
                </pre>
                </td>
            </tr>
        </tbody>
    </table>
    <br />
    </li>
    <li>注册刚才创建的https协议对象
    <table border="0" cellpadding="0" cellspacing="0" width="100%">
        <tbody>
            <tr>
                <td>
                <pre>Protocol.registerProtocol("https ", myhttps);<br />
                <br />
                </pre>
                </td>
            </tr>
        </tbody>
    </table>
    <br />
    </li>
    <li>然后按照普通编程方式打开https的目标地址，代码请参见test.NoCertificationHttpsGetSample</li>
</ul>
<p><a name="N1022A">处理代理服务器</a></p>
<p>HttpClient中使用代理服务器非常简单，调用HttpClient中setProxy方法就可以，方法的第一个参数是代理服务器地
址，第二个参数是端口号。另外HttpClient也支持SOCKS代理。</p>
<br />
<table border="0" cellpadding="0" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td>
            <pre>httpClient.getHostConfiguration().setProxy(hostName,port);<br />
            <br />
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<table border="0" cellpadding="0" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" /><br />
            <img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" /></td>
        </tr>
    </tbody>
</table>
<table align="right" cellpadding="0" cellspacing="0">
    <tbody>
        <tr align="right">
            <td><img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" /><br />
            <table border="0" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16" /><br />
                        </td>
                        <td align="right" valign="top"><a href="http://www.ibm.com/developerworks/cn/opensource/os-httpclient/#main" class="fbox"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p><a name="N1023C">结论</a></p>
<p>从上面的介绍中，可以知道HttpClient对http协议支持非常好，使用起来很简单，版本更新快，功能也很强大，具有足够的灵活性和扩
展性。对于想在Java应用中直接访问http资源的编程人员来说，HttpClient是一个不可多得的好工具。</p>
<br />
<br />
<p><a name="resources">参考资料 </a></p>
<ul>
    <li>Commons
    logging包含了各种各样的日志API的实现，读者可以通过站点http://jakarta.apache.org/commons
    /logging/得到详细的内容<br />
    <br />
    </li>
    <li>Commons
    codec包含了一些一般的解码/编码算法。包含了语音编码、十六进制、Base64和URL编码等，通过http:
    //jakarta.apache.org/commons/codec/可以得到详细的内容<br />
    <br />
    </li>
    <li>rfc2616是关于
    HTTP/1.1的文档，可以在http://www.faqs.org/rfcs/rfc2616.html上得到详细的内容，另外rfc1945是关
    于HTTP/1.0的文档，通过http://www.faqs.org/rfcs/rfc1945.html可以得到详细内容<br />
    <br />
    </li>
    <li>SSL――SSL
    是由 Netscape Communications Corporation 于 1994 年开发的，而 TLS V1.0 是由
    Internet Engineering Task Force（IETF）定义的标准，它基于 SSL
    V3.0，并且在使用的加密算法上与其有些许的不同。例如，SSL 使用 Message Authentication
    Code（MAC）算法来生成完整性校验值，而 TLS 应用密钥的 Hashing for Message Authentication
    Code（HMAC）算法。<br />
    <br />
    </li>
    <li>IBM JSSE提供了SSL（Secure Sockets
    Layer）和TLS（Transport Layer
    Security）的java实现，在http://www-03.ibm.com/servers/eserver/zseries/software
    /java/jsse.html中可以得到详细的信息<br />
    <br />
    </li>
    <li>Keytool是一个管理密钥和证书的工具。关于它详细的使用信
    息可以在http://www.doc.ic.ac.uk/csg/java/1.3.1docs/tooldocs/solaris
    /keytool.html上得到<br />
    <br />
    </li>
    <li>HTTPClient的主页是http://jakarta.apache.org
    /commons/httpclient/，你可以在这里得到关于HttpClient更加详细的信息</li>
</ul>
<img src ="http://www.blogjava.net/caizh2009/aggbug/317846.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/caizh2009/" target="_blank">小菜毛毛</a> 2010-04-09 14:38 <a href="http://www.blogjava.net/caizh2009/archive/2010/04/09/317846.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>