虽然在 JDK 的 java.net包中已经提供了访问 HTTP 协议的基本功能,但是对于大部分应用程序来说,JDK 本身提供的功能还不够丰富和灵活。HttpClient 是Apache Jakarta Common下的子项目,它是一个实现了 HTTP 协议的客户端编程工具。HttpClient 已经应用在很多的企业项目中,比如Apache Jakarta上很著名的开源项目Cactus和HTMLUnit 都使用到了HttpClient技术。 简单地说,HttpClient就是一个增强版的HttpURLConnection。HttpURLConnection可以做的事情HttpClient都可以做。HttpClient只是关注于如何发送请求、接收响应、以及管理HTTP连接。以下列出的是HttpClient提供的主要的功能:
- 实现了HTTP请求的所有的方法(GET、POST、PUT、HEAD 等)。
- 支持自动转向。
- 支持 HTTPS 协议。
- 支持代理服务器等。
HttpClient是一个客户端的Http通信实现库,可以用于发送HTTP请求,接收HTTP响应。但它不会缓存服务器的响应,不能执行HTML页面中嵌入的JavaScript代码,也不会对页面内容进行任何解析、处理。 HttpClient会自动维护与服务器之间的Session状态。比如,只要程序第一次使用HttpClient登录系统后,接下来就可以使用同一个HttpClient访问被保护的资源了。这和浏览器自动维护客户端与服务器之间的Session的功能类似。
使用 HttpClient 的基本步骤如下:
- 创建 HttpClient 的对象。
- 如果需要发送GET请求,则创建HttpGet对象;如果需要发送POST请求,则创建HttpPost对象。
- 如果需要发送请求参数,可以调用HttpGet、HttpPost都有的setParams()方法来添加请求参数。对于HttpPost对象而言,也可以调用setEntity()方法来设置请求参数。
- 调用HttpClient对象的execute()方法发送请求,该方法执行后会返回一个HttpResponse对象。
- 调用HttpResponse的getAllHeaders()、getHeaders()等方法可获得服务器的响应头;调用HttpResponse的getEntitiy()方法可以获得一个HttpEntity对象,该对象包装了服务器的响应内容,程序可以通过该对象获取服务器的响应内容。
- 释放连接,无论执行方法是否成功,都必须释放连接
第一步:创建一个JSP项目zghc,在它根目录下分别提供两个名为login.jsp和secret.jsp文件,其中login.jsp文件的源代码为:
secret.jsp的源代码为:
在上面的secret.jsp中我们先判断用户是否登录成功,如果没有登录成功是不能访问受保护的资源的。 第二步:创建一个Android项目,然后按照下图7.8所示设计主布局文件,其中上面表示用户名与密码的EditText的id值分别为name和pass,中间两个Button的onClick属性的值分别为directAccess和loginAccess,最下面的TextView的id为textView。 第三步:提供一个用来借助类HttpClient实现GET请求和POST请求的工具类,具体代码及说明如下:
public class HttpClientUtil {
// 创建DefaultHttpClient对象
public static HttpClient httpClient = new DefaultHttpClient();
public static final String BASE_URL = "http://10.0.2.2:8080/zghc/";
// 发送GET请求,返回服务器响应的字符串
public static String getRequest(String url) throws Exception {
HttpGet get = new HttpGet(url);// 创建一个HttpGet对象
HttpResponse httpResponse = httpClient.execute(get);// 发送GET请求,返回响应
// 如果服务器成功地返回响应
if (httpResponse.getStatusLine().getStatusCode() == 200) {
// 获取服务器响应字符串
String result = EntityUtils.toString(httpResponse.getEntity());
return result;
}
return null;
}
// 发送POST请求,返回服务器响应的字符串,其中params表示请求参数
public static String postRequest(String url, Map rawParams)
throws Exception {
HttpPost post = new HttpPost(url); // 创建HttpPost对象
// 对传递的参数进行封装
List params = new ArrayList();
for (String key : rawParams.keySet())// 封装请求参数
params.add(new BasicNameValuePair(key, rawParams.get(key)));
// 设置请求参数及URL编码
post.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
HttpResponse httpResponse = httpClient.execute(post); // 发送POST请求
// 如果服务器成功地返回响应
if (httpResponse.getStatusLine().getStatusCode() == 200) {
// 获取服务器响应字符串
String result = EntityUtils.toString(httpResponse.getEntity());
return result;
}
return null;
}
}
当使用HttpClient执行HTTP POST调用时,通常将编码到URL中的键值对参数作为HTTP 请求的一部分传递。要通过HttpClient实现此功能,必须创建一个包含NameValuePair对象实例的列表,然后使用UrlEncodedFormEntity对象包装该列表。NameValuePair包装了一个键值组合,UrlEncodedFormEntity类知道如何编写适合HTTP调用(通常为POST调用)的NameValuePair对象列表。创建UrlEncodedFormEntity之后,可以将HttpPost的实体类型设置为UrlEncodedFormEntity,然后执行该请求了。
提示: 使用HttpClient不仅能够以字符串形式获取返回服务器端的内容,还可以以InputStream流的形式返回服务器端处理的结果,这是因为可以通过HttpEntity类的getContent ()方法得到一个InputStream,所以使用HttpClient类可以得到服务器端任何类型的数据。我们在浏览器客户端所执行的大多数操作HttpClient都能够模拟,例如:提交表单、查询数据、上传下载文档、页面跳转、Session存储等。 注意: HttpEntity中的内容只能读取一次,如果多次调用它的getContent()方法则会报如下异常:java.lang.IllegalStateException: Content has been consumed 提示: 在GET请求中的Uri也可以带有参数,不过出于安全考虑,在需要传递参数时一般情况下使用POST方式。带参数的URI有以下几种实现方法:
- HttpGet get = new HttpGet(“http:// 10.0.2.2:8080/zghc/login.jsp?name=wx&pass=wx”);
- 通过HttpClient程序包提供的URIUtils工具类:
URI uri = URIUtils.createURI("http", "10.0.2.2 ", 8080, "/zghc/login.jsp ",
"name=wx&pass=wx ", null);
HttpUriRequest request = new HttpGet(uri);
System.out.println(request.getURI());
如果参数中含有中文,需将参数进行URLEncoding处理,如:
String param = "wx=" + URLEncoder.encode("张三", "UTF-8") + "&wx=wx";
URI uri = URIUtils.createURI("http", "10.0.2.2 ", 8080, "/zghc/login.jsp ", param, null);
System.out.println(uri);
- 对于参数的URLEncoding处理,我们还可以通过HttpClient程序包中的URLEncodedUtils工具类直观的生成URI,如:
List params = new ArrayList();
params.add(new BasicNameValuePair("name", "张三"));
params.add(new BasicNameValuePair("pass", "wx"));
String param = URLEncodedUtils.format(params, "UTF-8");
URI uri = URIUtils.createURI("http", "10.0.2.2 ", 8080, "/zghc/login.jsp ", param, null);
System.out.println(uri);
在POST请求中,我们可以通过UrlEncodedFormEntity类创建的对象模拟传统的HTML表单传送POST请求中的参数。比如:
用户名:
密码:
我们可以用下面的代码实现:
List formParams = new ArrayList();
formParams.add(new BasicNameValuePair("name", "wx"));
formParams.add(new BasicNameValuePair("pass", "wx"));
HttpEntity entity = new UrlEncodedFormEntity(formParams, "UTF-8");
HttpPost post = new HttpPost("http://10.0.2.2:8080/ zghc/login.jsp");
post.setEntity(entity);
当然,如果想查看HTTP数据格式,可以通过HttpEntity对象的各种方法取得。如:
List formParams = new ArrayList();
formParams.add(new BasicNameValuePair("param1", "中国"));
formParams.add(new BasicNameValuePair("param2", "value2"));
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formParams, "UTF-8");
System.out.println(entity.getContentType());
System.out.println(entity.getContentLength());
System.out.println(EntityUtils.toString(entity));
对应的输出结果为:
Content-Type: application/x-www-form-urlencoded
15
name=wx&pass=pass
第四步:编写Activity类,代码如下:
public class MainActivity extends Activity {
private TextView textView =null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.textView);
}
public void loginAccess(View view) { //先登录后访问受限制的资源
String url = HttpClientUtil.BASE_URL + "login.jsp";
EditText nameET = (EditText) findViewById(R.id.name);
EditText passET = (EditText) findViewById(R.id.pass);
String name = nameET.getText().toString().trim();
String pass = passET.getText().toString().trim();
Map map = new HashMap();
map.put("name", name);
map.put("pass", pass);
try {
String temp = HttpClientUtil.postRequest(url, map);
if ("SUCCESS".equals(temp.trim())) {
directAccess(view);
} else {
textView.setText("用户名或密码错误,请重新登录");
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void directAccess(View view){ //未登录直接访问受限制的资源
String url = HttpClientUtil.BASE_URL + "secret.jsp";
String res = null;
try {
res = HttpClientUtil.getRequest(url);
} catch (Exception e) {
e.printStackTrace();
}
textView.setText(res);
}
}
第五步:在功能清单文件中添加网络访问权限:
运行程序:先将JSP项目部署到tomcat中,然后运行Android程序,结果如下图所示。 未登录直接访问
登录失败
成功登录后访问
使用HttpClient中文乱码问题:
- 方案一:在用EntityUtils.toString()取得返回字符串的时候,默认编码为ISO-8859-1,需要指定toString的第二个参数为服务器端的编码格式。比如: 服务器端:response.setCharacterEncoding(“UTF-8”); 客户端:String result = EntityUtils.toString(httpResponse.getEntity(),“UTF-8”);
- 方案二: String message = “我的测试消息”; HttpServer发送时:message=new String(message.getBytes(“UTF-8”),“ISO-8859-1”); Android接收时: message=new String(message.getBytes(“ISO-8859-1”),“UTF-8”);
第一步:首先在功能清单文件中添加网络访问权限,然后在主布局文件中提供一个让用户输入待查询的电话号码的id值为phoneNum的EditText、一个用来显示号码地址的id为result的TextView、一个onClick属性值为fun的Button控件。 第二步:修改MainActivity类的代码如下所示:
public class MainActivity extends Activity {
private TextView result;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
result = (TextView) findViewById(R.id.result);
}
public void fun(View view) {
EditText phoneNumET = (EditText) findViewById(R.id.phoneNum);
String phoneNum = phoneNumET.getText().toString().trim(); // 手机号码
// 简单判断用户输入的手机号码是否合法
if ("".equals(phoneNum) || phoneNum.length()
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?