HttpClient系列之——HttpClient/Jsoup 请求

1. HttpClient 请求

HttpClient 是 Apache Jakarta Common 下的子项目,可以用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。
使用 HttpClient 需要以下 6 个步骤:
1. 创建 HttpClient 的实例
2. 创建某种连接方法的实例,HttpGet或HttpPost实例。
3. 调用第一步中创建好的实例的 execute 方法来执行第二步中创建好的 method 实例
4. 读 response
5. 释放连接。无论执行方法是否成功,都必须释放连接
6. 对得到后的内容进行处理
以上摘抄百度。

 

1.1 Get 请求示例

使用apache HttpComponents-client 向服务器发送Get请求,并处理返回。

    a)HttpClient 版本

 
  <dependency>
   <groupId>org.apache.httpcomponents</groupId>
   <artifactId>httpclient</artifactId>
   <version>4.2.5</version>
  </dependency>

    b) 服务器处理:从请求中获取username和password两个参数,打印到控制台并以JSON的方式响应到请求端

@WebServlet(value = "/json.html")
public class PresponseJsonServlet extends HttpServlet {
    private static final long    serialVersionUID    = 1L;
 
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse respthrows ServletException, IOException {
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        System.out.println(String.format("username=%s,password=%s"usernamepassword));
        Map<String, String> data = new HashMap<String, String>();
        data.put("username"username);
        data.put("password"password);
 
        resp.reset();
        resp.setCharacterEncoding("UTF-8");
        resp.setContentType("application/json; charset=utf-8");
        resp.getWriter().write(JSON.toJSONString(data));
        resp.getWriter().close();
    }
}   
 
 

    c) HttpClient 发送Get请求

publicclassHttpClientGet{
publicstaticvoid main(String[] args)throwsException{
 URI uri =newURIBuilder().setScheme("http").setHost("localhost").setPort(8080)
                                  .setPath("/part1/json.html").setParameter("username","myname")
                                  .setParameter("password","mypassword").build();
HttpGet httpGet =newHttpGet(uri);
System.out.println(httpGet.getURI());
 
HttpClient httpClient =newDefaultHttpClient();
HttpResponse response = httpClient.execute(httpGet);
System.out.println(response.getStatusLine());
 
HttpEntity entity = response.getEntity();
if(null!= entity){
System.out.println(EntityUtils.toString(entity));
}
HttpClientUtils.closeQuietly(httpClient);//关闭资源
}
}
 
    d)控制台输出
http://localhost:8080/part1/json.html?username=myname&password=mypassword
HTTP/1.1 200 OK
{"username":"myname","password":"mypassword"}  
    

1.2 创建请求

      a)使用 apache 提供的URIBuilder创建        
URI uri =newURIBuilder().setScheme("http").setHost("localhost")
.setPort(8080).setPath("/part1/json.html")
.build();
    b) 使用apache URIUtils创建。此方法为HttpClient3.x中的方法,在HttpClient4.x中已废弃,官方建议使用URIBuilder来创建
URI uri =URIUtils.createURI("http","localhost",8080,"/part1/json.html","username=myname&password=mypassword",null);
 
    c)在创建HttpGet或HttpPost时直接将URL传递到构造方法参数中
HttpGet httpGet =newHttpGet("http://localhost:8080/part1/json.html?username=myname&password=mypassword");
HttpPost httpPost =newHttpPost("http://localhost:8080/part1/json.html?username=myname&password=mypassword");
 

1.2 请求参数

    a)URIBuilder对象提供了setParameter(...)方法设置参数
URI uri =newURIBuilder().setScheme("http").setHost("localhost")
.setPort(8080).setPath("/part1/json.html").setParameter("username","中文名")
.setParameter("password","mypassword")
.build();
 
 b)创建请求时直接写在URL里。如1.1创建请求->c)。
     以上两种方法式传递参数时,如果包含中文不能处理编码问题。如果需要处理编码问题可以使用下面这种方式:
    使用 apache httpclient 提供的URIEncodeUtils工具类处理参数编码问题
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("username", "中文名"));
params.add(new BasicNameValuePair("password", "mypassword"));
String encodedParam = URLEncodedUtils.format(params, Charset.forName("UTF-8")); 
HttpGet httpGet = new HttpGet("http://localhost:8080/part1/json.html?"+encodedParam);  
HttpGet httpGet = new HttpGet(uri.toString()+"?"+encodedParam);//创建URI对象时不要设置参数
     c)对于POST请求来说,除了以上两种方式,HttpPost接口还提供了一个setEntity(...)方法设置Http报文信息。这些信息可以在请求或响应中找到。通过这种方式也可以达到参数传递的效果。而在某些请求中时还必须使用该来设置请求信息,比如文件上传...
HttpPost httppost = new HttpPost(URL);
MultipartEntity mpEntity = new MultipartEntity();
File file = new File("D://xxx.txt");
ContentBody cbFile = new FileBody(file, "text/plain");
mpEntity.addPart("returnInfo", cbFile);
mpEntity.addPart("sign", new StringBody(RSAUtil.sign(PRIVATE_KEY, new FileInputStream(file))));
httppost.setEntity(mpEntity);
System.out.println("executing request " + httppost.getRequestLine());
HttpResponse response = httpclient.execute(httppost);
 

1.2 执行请求

apache HttpClient 执行一个http请求时,需要创建一个HttpClient对象。
HttpClient接口有三个子类:
  
通常情况下,使用DefaultHttpClient类创建HttpClient实例即可。
HttpClient httpClient = new DefaultHttpClient();
HttpResponse response = httpClient.execute(httpGet);
 
可以看出apache 在设计该类时将它设计为线程安全类,因此使用该类创建HttpClient实体时,可以将它设计成单例或共有的,不用每次都实例化。
HttpClient最终连接服务器使用Socket连接服务器,因此就面临着资源关闭问题。
httpClient.getConnectionManager().shutdown();
HttpClientUtils.closeQuietly(httpClient);
  使用HttpClientUtils.closeQuietly(xxx)关闭资源时与上面那种方式是一样的。
 

2. Jsoup请求

jsoup 是一款Java 的HTML解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API,可通过DOM,CSS以及类似于jQuery的操作方法来取出和操作数据。(百度百科)
 
这里介绍的Jsoup API 只有向服务端发送请求的部分,可以使用该部分API来代替HttpClient的使用;
并没有涉及Jsoup解析HTMl文档的方面,如果想了解如何使用Jsoup解析HTML文档,可以参考:

jsoup Cookbook(中文版)


 <dependency>
	<groupId>org.jsoup</groupId>
	<artifactId>jsoup</artifactId>
	<version>1.8.3</version>
</dependency>

2.1 创建请求

使用Jsoup创建get/post请求时比Apache HttpClient要省力得多。只需要一两行代码即可。
String url = "http://localhost:8080/part1/json.html";
Response execute = Jsoup.connect(url).execute();
System.out.println(execute.body());
 
这样便可向url地址发送请求,此处虽然没有指定请求方式,默认以Get方式发起请求。
注:Jsoup解析响应时经常会产生如下异常:
org.jsoup.UnsupportedMimeTypeException:Unhandled content type.Must be text/*, application/xml, or application/xhtml+xml. Mimetype=application/json;charset=UTF-8, URL=http://localhost:8080/part1/json.html
at org.jsoup.helper.HttpConnection$Response.execute(HttpConnection.java:547)
at org.jsoup.helper.HttpConnection$Response.execute(HttpConnection.java:493)
at org.jsoup.helper.HttpConnection.execute(HttpConnection.java:205)
at com.wysa.httpClient.JsoupGet.main(JsoupGet.java:17)
原因是Jsoup所支持的响应头没有HttpClient 那么全。
Jsoup的 Connection接口 提供了 ignoreContentType(boolean ...)方法来避免这种错误。当此方法设置为true时,Jsoup解析响应就不会去验证响应头信息。

2.2 执行Get请求

String url = "http://localhost:8080/part1/json.html";
Map<String, String> data = new HashMap<String, String>();
	data.put("username", "myusername");
	data.put("password", "mypassword");
Response response = Jsoup.connect(url).data(data).method(Method.GET).ignoreContentType(true).execute();
System.out.println(response.body());
 
服务端响应:
{"username":"myusername","password":"mypassword"}
 

2.3 执行Post请求

String url = "http://localhost:8080/part1/json.html";
Map<String, String> data = new HashMap<String, String>();
	data.put("username", "myusername");
	data.put("password", "mypassword");
Response response = Jsoup.connect(url).data(data).method(Method.POST).ignoreContentType(true).execute();
System.out.println(response.body());
 
服务端响应:
{"username":"myusername","password":"mypassword"}
可以看出,Jsoup向服务端发送Get/Post请求时,差别相当少,仅仅只需要说明请求的类型即可。
Connection data(Collection<KeyVal> data);
Connection data(String key, String value);
Connection data(String key, String filename, InputStream inputStream);
Connection data(Map<String, String> data);
Connection data(String... keyvals)
 Connection提供的参数设置很方便,而HttpClient要想样使用还得自己再封装一次。
Jsoup 的Connection接口还提供了get和post的快捷方法。
 Document get() throws IOException; 
 Document post()  throws  IOException;
如:
 Document document = Jsoup.connect(url).data(data).get();
 
区别在于这两个方法的返回值类型为Document,它更倾向于在解析HTML文档时使用。
使用Connection 接口的execute()方法 执行请求时返回值为org.jsoup.Connection.Response。个人认为此API在只想获取服务端返回值时使用更为合适。
 

3. Jsoup/HttpClient 请求比较

1.Jsoup向服务端发送请求的API更为简洁,个人最欣赏的还是Jsoup传递参数的机制比HttpClient方便太多。
2.Jsoup另一亮点便是上传文件的API比HttpClient简单。详情参见:Servlet3.0 文件上传
当然这些比较仅仅在于发送请求方面比较出来的,并不是说Jsoup 就比HttpClient好。两个项目是在不同的应用目的下产生的,各有各的优势。这里只是把它们部分共同的功能列出学习和参考。

猜你喜欢

转载自yeyusir.iteye.com/blog/2249612