虽然在 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 的基本步骤如下:

  1. 创建 HttpClient 的对象。
  2. 如果需要发送GET请求,则创建HttpGet对象;如果需要发送POST请求,则创建HttpPost对象。
  3. 如果需要发送请求参数,可以调用HttpGet、HttpPost都有的setParams()方法来添加请求参数。对于HttpPost对象而言,也可以调用setEntity()方法来设置请求参数。
  4. 调用HttpClient对象的execute()方法发送请求,该方法执行后会返回一个HttpResponse对象。
  5. 调用HttpResponse的getAllHeaders()、getHeaders()等方法可获得服务器的响应头;调用HttpResponse的getEntitiy()方法可以获得一个HttpEntity对象,该对象包装了服务器的响应内容,程序可以通过该对象获取服务器的响应内容。
  6. 释放连接,无论执行方法是否成功,都必须释放连接

示例:演示如何使用HttpClient访问被保护的资源。

第一步:创建一个JSP项目zghc,在它根目录下分别提供两个名为login.jsp和secret.jsp文件,其中login.jsp文件的源代码为:

<%@ page contentType="text/html; charset=utf-8" language="java"%>
<%String name = request.getParameter("name");String pass = request.getParameter("pass");if (name.equals("hc") && pass.equals("hc")) {session.setAttribute("user", name);out.println("SUCCESS");} else {out.println("ERROR");}
%>

secret.jsp的源代码为:

<%@ page contentType="text/html; charset=utf-8" language="java" %>
<%Object user = session.getAttribute("user");if(user != null && user.toString().trim().equals("wx")){out.println("受保护的资源,只有成功登录的用户才可访问到该资源"); }else{out.println("您没有被授权访问该页面"); }
%>

在上面的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<String, String> rawParams)throws Exception {HttpPost post = new HttpPost(url); // 创建HttpPost对象// 对传递的参数进行封装List<NameValuePair> params = new ArrayList<NameValuePair>();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<NameValuePair> params = new ArrayList<NameValuePair>();
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请求中的参数。比如:

<form action="http://localhost/zghc/login.jsp" method="POST">  用户名: <input type="text" name="name" value="wx"/>  密码:<input type="password" name="pass" value="wx"/>  <inupt type="submit" value="登录"/>
</form>

我们可以用下面的代码实现:

List<NameValuePair> formParams = new ArrayList<NameValuePair>();
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<NameValuePair> formParams = new ArrayList<NameValuePair>();
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;@Overridepublic 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<String, String> map = new HashMap<String, String>();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);}
}

第五步:在功能清单文件中添加网络访问权限:

<uses-permission android:name="android.permission.INTERNET"/>

运行程序:先将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;@Overridepublic 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() < 7) {phoneNumET.setError("您输入的手机号码有误!");// 给出错误提示phoneNumET.requestFocus(); //EditText再次获取焦点result.setText("");   // 将显示查询结果的TextView清空return;}getPhoneNumAddress(phoneNum); // 查询手机号码信息}public void getPhoneNumAddress(String phoneSec) {// 手机号段归属地查询String url = "http://webservice.webxml.com.cn/WebServices/
MobileCodeWS.asmx/op=getMobileCodeInfo";// 定义待请求的URLHttpClient client = new DefaultHttpClient(); // 创建HttpClient实例HttpPost post = new HttpPost(url); // 根据URL创建HttpPost实例List<NameValuePair> params = new ArrayList<NameValuePair>();// 设置需要传递的参数params.add(new BasicNameValuePair("mobileCode", phoneSec));params.add(new BasicNameValuePair("userId", ""));try {// 设置URL编码post.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));HttpResponse response = client.execute(post); // 发送请求并获取反馈// 判断请求是否成功处理if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {// 解析返回的内容String address = EntityUtils.toString(response.getEntity());// 将查询结果经过解析后显示在TextView中result.setText(filterHtml(address));}} catch (Exception e) {e.printStackTrace();}}private String filterHtml(String source) {// 使用正则表达式过滤HTML标记if (null == source) {return "";}return source.replaceAll("</?[^>]+>", "").trim();}
}

运行程序,当用户输入待查询号码、单击查询按钮后,会在下方看到对应的地址信息,如下图7.18所示。

号码归属地查询结果
如果每次通话显示归属地,都请求网络,一是受网络状态的制约,二是会造成不必要的流量浪费,实际应用中的解决办法是将常用的号码归属地信息保存到数据库中,当软件运行的时候先从数据库中查询,数据库中不存在时,才从网络中获取。

使用HttpClient访问WEB资源相关推荐

  1. Strus2_Action中访问Web资源

    1.什么是web资源? 如:HttpServletRequest,HttpSession,ServletContext等原生的ServletAPI 2.为什么访问web资源? B/S架构的应用的con ...

  2. Struts2 学习系列 (2) 访问web资源

    2019独角兽企业重金招聘Python工程师标准>>> 在 Action 中, 可以通过以下方式访问 web 的 HttpSession, HttpServletRequest, H ...

  3. 在Firefox中通过AJAX跨域访问Web资源

    一.解决在firefox中无法跨域访问的问题 AJAX从本质上讲就是命名用XMLHttpRequest组件来向服务端发送HTTP请求,请接收相应信息.至于成功接收到响应信息后的操作,就和普通的Web客 ...

  4. Android网络编程使用HttpClient访问web站点

    HttpClientDemo.java界面就是两个按钮和一个文本框 /** 用HttpClientlai 来访问提交请求,接收响应* A,发送GET请求* 1,创建HttpClient对象:HttpC ...

  5. 【commons-httpclient】Java中HttpClient工具访问Web请求

    注意jar包是: HttpClient工具使用 HttpClient 是 Apache Jakarta Common 下的子项目,可以用来提供高效的.最新的.功能丰富的支持 HTTP 协议的客户端编程 ...

  6. springmvc:BeanNameViewResolver访问内部资源视图对象和访问外部资源视图对象

    <!-- 处理器映射器 --><bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMa ...

  7. 通过nginx访问web,出现ERR_CONTENT_LENGTH_MISMATCH解决方法

    问题描述 前端页面加载css,js文件或者png图片的时候,经常出现ERR_CONTENT_LENGTH_MISMATCH的报错情况. 查找问题 在单独打开hearder中css,js的网络地址是能打 ...

  8. vue打包后css路径_Vue打包后访问静态资源路径问题

    Vue打包后访问静态资源路径问题 Vue介绍中static文件夹里放的是静态资源目录,如图片.字体等. 我们发现运行npm run start后本地图片路径是没问题的,但是打包上传后会怎么样呢? 我们 ...

  9. SpringBoot中访问静态资源

    场景 在SpringBoot中加载静态资源和在普通的web应用中不一样. 默认情况下: SpringBoot从classpath的/static,/public或者 /META-INF/resourc ...

最新文章

  1. 近10年数据智能团队建设,联想总结了由内而外的发展经验 | 专访联想集团副总裁田日辉...
  2. 使用final关键字修饰一个变量时,是引用不能变,还是引用的对象不能变?
  3. 进站公交车碾起积水溅上轿车两男子驾车撞伤公交司机
  4. [css] 怎么设置可点击的元素上强制手型?
  5. protobuf2和3同时安装_安装protobuf可能遇到的问题
  6. vb读出二进制文件,合并两个文件
  7. 【jeecg移动开发能力】Jeecg 重磅来袭,强大移动报表配置能力,一次配置七种展现风格
  8. 大数据技术周报第 002 期
  9. HTTPS上线过程说明
  10. ORA-12547: TNS:lost contact导致数据库无法启动
  11. SAP License:SAP 移动类型详解
  12. 谈谈 JDK 和 SAPMachine 的关系
  13. 情境领导者的三体思维
  14. 经纬能源安全稳定怎样理财收益最大?怎样理财才干收益最大?
  15. java 改变图片某个坐标点的颜色,并返回给前台显示
  16. 持NPDP证书在深圳可享受子女入学、医疗保健、安居保障等福利
  17. 2019 Multi-University Training Contest 7 部分补题
  18. 源码编译安装部署LAMP平台(使用Apache,MySQL与PHP搭建Discuz论坛实例)
  19. 订单中心探索业务系统数据预置助力快交付之路
  20. 西乔说要把「神秘的程序员们」当做一个文化产品来做

热门文章

  1. Prolog教程 5
  2. java员工试用期工作总结
  3. 融媒发展背景下学龄前儿童交通安全主题绘本创作启示
  4. 【软件测试】身为测试人,经常背锅的我该咋办?
  5. 使用Windows XP 的任务计划
  6. 如何修改linux文件句柄数,Linux服务器修改文件句柄数和用户最大进程数限制
  7. 华南理工大学计算机基础知识随堂,华南理工计算机基础随堂练习.docx
  8. 国产网络损伤仪SandStorm -- 如何连接设备
  9. 评论对软件品牌很重要:有效地生成和管理评论
  10. 2022.10.4 英语背诵