环境准备
无论是PC ,还是移动终端,传输的协议始终是HTTP 协议。
学习路线
1. 简单应用 HttpClient ,登录和不登录的方式, 截取数据
2. 通过 GAE 和 HttpClient 开发出对某个应用的标准 API 数据 (XML 格式 ) 。
3. 结合 HttpClient 和 HTTP 协议,了解 HttpClient 的基本实现原理
准备与 HttpClient 相关的 Jar 包:
# commons-logging-x.x.x.jar # commons-codec-x.x.x.jar # httpcore-x.x.x.jar # httpclient-x.x.x.jar |
概念术语
HTTP 消息:包括请求 (Request) 、回应 (Response)
消息的组成:消息头 (Header) 、消息实体 (Entity)
消息头的组成
通过 ieHttpHeader 截获了如下的头
请求的头:
GET /cn/ HTTP/1.1 Accept: Accept-Language: zh-cn Accept-Encoding: gzip, deflate User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) Host: www.huawei.com Connection: Keep-Alive Cookie: JSESSIONID=0000PtOOnIvtTar62-lClbyAO-m:12n56k2cu |
响应的头:
HTTP/1.1 200 OK Set-Cookie: MMwwwURL=235eb216f488bb88993cba88; path= Date: Sat, 22 Aug 2009 03:21:59 GMT Server: Apache Accept-Ranges: bytes Vary: Accept-Encoding Content-Encoding: gzip Content-Length: 7320 Keep-Alive: timeout=5, max=100 Connection: Keep-Alive Content-Type: text/html |
可知 , Header 有如下特点:
1. 除了第一行之外,其他的都是名 - 值对;请求和响应的区别是非常大的。尤其是第一行。第一行特别提取出 Method, 协议名等作为 HttpClient 的一个特征。
2. 名 - 值对的存在是为了让对方更清楚的了解发送方的意图, HttpClient 将其称为 Header Fields 。在 HttpClient 中用 Header 类来表示。
消息实体 (Entity)
应该是指响应中回复的数据,指 MIME 的类型, Response 字段中有 Content-Type 就是用来描述 Entity 的类型 。
有以下 MIME 类型:
普通文本 .txt text/plain RTF 文本 .rtf application/rtf GIF 图形 .gif image/gif JPEG 图形 .ipeg,.jpg image/jpeg au 声音文件 .au audio/basic MIDI 音乐文件 mid,.midi audio/midi,audio/x-midi RealAudio 音乐文件 .ra, .ram audio/x-pn-realaudio MPEG 文件 .mpg,.mpeg video/mpeg AVI 文件 .avi video/x-msvideo GZIP 文件 .gz application/x-gzip TAR 文件 .tar application/x-tar |
应用流程
第一:得到登录的页面
用 Get 方法去测试,查看以下结果:
1. 是否得到预期的页面?指一些数据,比如从 IE 上能显示的 HTML BODY
2. 是否得到 Sessions cookie ?
一般登录进去之后,才会有这样的 Sessions Cookie ,记得上一讲中的 Http Response Header 吗,里面的 Set Cookies ,可能就包含 Sessions Cookie 。如果此时没有 Set Cookies 肯定说明此时 Session 没有建立。说明你还需要做一步工作,就是 " 建立 Sessions" 。 ( 引申一下, 即使存在 Set Cookie 这样的字段, 一定保证里面设置的就是 Session 吗? 也不一定, 保险的做法是,按照浏览器的习惯,从主页,再到登录页面,主页的目的只是为了获取必要的 Cookie 不要一步登天,当然,我们可以测试一下先,免得做不必要的登录主页,获取 Cookie 的操作 ) 。
如果,上面的 set cookie 你也有了,请求的 URL 也确认无误,但还是得不到预期的登录界面。很可能就是对方有个字段没有设置: User-Agent , 这个是指明你采用了哪个客户端向服务器发送请求,比如常用的有 IE 、 FF 、 Chrome ,设置主流的浏览器就成。
第二:建立 Session
这是在第一步失败的情况下需要的工作。通常的情况是,从主页去 Get 一把,从而得到 Cookie 。下次 Login 请求的时候,将这些 Cookie 带进去。
HttpClient 提供了一套自动机制帮我们发送 Cookie , Cookie Store ,把 Response 中的 Cookie 放置其中,并在发送的时候,帮我们发过去 ( 如果没有发送过去,检查 Cookie Store 是否为同一个 ) 。
如果依然没有发送过去,这个时候就要检测 Cookie Scope , 比如:
A cookie for host "jakarta.apache.org" will not be sent to host "tomcat.apache.org". A cookie for domain ".apache.org" will be sent to both |
注意, BT 的来了:
A cookie for host "apache.org", without the leading dot, will not be sent to "jakarta.apache.org".
如果还不行 ... 崩溃 ... 先别看了,以后再去这里寻求帮助好了
第三:分析表单
分析的方式是通过浏览器来的。建议过配置文件去灵活转化,不必进行复杂的表单解析工作。
OK ,可以按照 Browser 的习惯处理 HttpClient 的应用:
1. 得到必要的 Cookie 包括 Session id , 这个时候,我们还是用主页登录比较好。此时如果主页没有可用的信息,则我们只需要处理 Response 中的 Cookie 字段就好了。
2. 找到访问的路径。设置必要的参数对和必要的 URL( 包括表单项目 ) 。
功能封装
这里主要对一些 HttpClient 的基本功能实现封装, 封装成自己的 API ,供后续应用进行调用。下例可以将指定 URL 的内容获取过来。
处理 Entity 的实例:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
public class ClientConnectionRelease {
/**
* 处理一个实体
*
* @param entity
*/
private static StringBuffer processEntity(HttpEntity entity) {
StringBuffer sb = new StringBuffer();
InputStreamReader iReader = null;
try {
// 从消息实体中获取输入流对象
InputStream inputStream = entity.getContent();
iReader = new InputStreamReader(inputStream);
BufferedReader reader = new BufferedReader(iReader);
String line = null;
// 用reader.ready()是不行的,这是用来判断此流是否已准备好被读取
while ((line = reader.readLine()) != null) {
sb.append(line + "\r\n");
}
} catch (Exception ex) {
ex.printStackTrace();
} finally {
try {
iReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return sb;
}
/**
* main方法
*
* @param args
* @throws Exception
*/
public final static void main(String[] args) throws Exception {
// 创建HttpClient实例
HttpClient httpclient = new DefaultHttpClient();
// 创建Get方法实例
HttpGet httpget = new HttpGet("http://www.baidu.com/");
// HttpClient执行Get方法实例后得到响应
HttpResponse response = httpclient.execute(httpget);
// 从响应中获取消息实体,如果有的话
HttpEntity entity = response.getEntity();
// 处理消息实体中的内容
try {
StringBuffer sb = processEntity(entity);
System.out.println(sb);
} catch (RuntimeException ex) {
// 终止执行请求
httpget.abort();
throw ex;
}
// 释放连接
httpclient.getConnectionManager().shutdown();
}
}
HttpClient相关jar包见附件!