首页 > 技术文章 > Java网络编程:利用apache的HttpClient包进行http操作

51kata 2016-01-09 15:56 原文

本文介绍如何利用apache的HttpClient包进行http操作,包括get操作和post操作。

一、下面的代码是对HttpClient包的封装,以便于更好的编写应用代码。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.httpclient.Cookie;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.cookie.CookiePolicy;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.httpclient.util.URIUtil;
import org.apache.commons.lang.StringUtils;


public class MyHttpClient {
    private HttpClient httpClient;
    private String cookies;

    public MyHttpClient(String ip) {
        this(ip, 80);
    }

    public MyHttpClient(String ip, int port) {
        httpClient = new HttpClient();
        httpClient.getHostConfiguration().setHost(ip, port, "http");
        httpClient.getParams().setCookiePolicy(
                CookiePolicy.BROWSER_COMPATIBILITY);
    }

    public String getCookies(){
        return cookies;
    }

    public void setCookies(String cookies){
        this.cookies = cookies;
    }

    public String doGet(String url) throws IOException{
        return doGet(url,null);
    }

    public String doGet(String url, String paras) throws IOException {
        GetMethod method = new GetMethod(url);
        if (StringUtils.isNotBlank(paras)) {
            method.setQueryString(URIUtil.encodeQuery(paras));
        }
        return sendRequest(method);
    }

    public String doPost(String url) throws IOException{
        return doPost(url,new HashMap<String,String>());
    }

    public String doPost(String url, String paras) throws IOException {
        Map<String,String> paraMap = new HashMap<String,String>();
        String[] values = paras.split("&");
        for(String value:values){
            String[] item = value.split("=");
            if(item.length==2){
                paraMap.put(item[0].trim(), item[1].trim());
            }
        }
        return doPost(url,paraMap);
    }

    public String doPost(String url, Map<String,String> paras) throws IOException{
        int index=0;
        NameValuePair[] data = new NameValuePair[paras.size()];
        for(Map.Entry<String,String> entry:paras.entrySet()){
            data[index++] = new NameValuePair(entry.getKey(),entry.getValue());
        }
        return doPost(url,data);
    }

    private String doPost(String url, NameValuePair[] data) throws IOException{
        PostMethod method = new PostMethod(url);
        method.setRequestBody(data);
        method.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET,"utf-8");
        return sendRequest(method);
    }

    private String sendRequest(HttpMethod method) throws IOException{
        StringBuffer response = new StringBuffer();
        try {
            method.setRequestHeader("Cookie", cookies);
            httpClient.executeMethod(method);

            if (method.getStatusCode() == HttpStatus.SC_OK) {
                response.append(getResponseBody(method));
            }else if(method.getStatusCode() == HttpStatus.SC_MOVED_TEMPORARILY){
                //302 重定向
                response.append(getResponseHeader(method));
            }else {
                System.out.println("response statuscode : "
                        + method.getStatusCode());
                throw new IllegalStateException("response statuscode : "
                        + method.getStatusCode());
            }
            fetchCookies();
        }finally {
            method.releaseConnection();
        }
        return response.toString();
    }

    private void fetchCookies(){
        Cookie[] values = httpClient.getState().getCookies();
        StringBuffer cookieBuffer = new StringBuffer();
        for (Cookie c : values)
        {
            cookieBuffer.append(c.toString()).append(";");
        }
        cookies = cookieBuffer.toString();
    }

    private String getResponseBody(HttpMethod method) throws IOException, IOException {
        StringBuffer response = new StringBuffer();
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new InputStreamReader(
                    method.getResponseBodyAsStream(), "UTF-8"));
            String line;
            while ((line = reader.readLine()) != null) {
                response.append(line).append(
                        System.getProperty("line.separator"));
            }
        }finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                }
            }
        }
        return response.toString();
    }

    private String getResponseHeader(HttpMethod method){
        StringBuffer response = new StringBuffer();
        Header[] headers = method.getResponseHeaders();
        for(Header header:headers){
            String line = header.getName()+" : "+header.getValue();
            response.append(line);
            response.append(System.getProperty("line.separator"));
        }
        return response.toString();
    }

}

说明:上面代码中doGet方法中的 语句 String encodeQuery = URIUtil.encodeQuery(paras);

存在一点问题,当url部门有特殊字符,如空格、+ 号等,这些字符需要被编码。

这时需要换成 String encodeQuery = URIUtil.encodePath(paras); 语句,即用encodePath方法替代encodeQuery方法。

 

二、下面来进行实际的使用举例

1、简单的get操作

下面的代码完成对一个url的get操作。我们封装了两个doGet操作,一个是带参数的,一个是不带参数的。待参数的参数格式如 name1=value1&name2=value2

  MyHttpClient httpClient = new MyHttpClient("xxxx");  //xxxx是web服务器的地址
  String result = httpClient.doGet(url);  //url是请求的url地址
  System.out.println(result);

2、简单的post操作

下面的代码完成对一个url的post操作.

MyHttpClient httpClient = new MyHttpClient("localhost");
Map<String,String> paras = new HashMap<String,String>();
paras.put("para1", "value1");
paras.put("para2", "value2");

String result = httpClient.doPost(url,paras);
System.out.println(result);

3、有重定向的get操作

如果发起的一个get操作,被服务器重定向到一个新的url。这时我们封装的doGet操作返回的是新的url(重定向后的)对应的信息。

4、有重定向的post操作

如果发起的一个post操作,被服务器重定向到一个新的url。我们封装的doPost操作,与doGet操作返回的结果不同,doPost是返回重定向头信息,而不是新的url的信息。如返回如下的信息,其中Location对应的值login就是重定向的url

Server : Apache-Coyote/1.1
Set-Cookie : JSESSIONID=8115A882086E7F27809FDF24213F82F5; Path=/boot/; HttpOnly
Set-Cookie :Expires=Thu, 01-Jan-1970 00:00:10 GMT
Location : login
Content-Length : 0
Date : Sat, 09 Jan 2016 07:41:21 GMT

5、需要登录的请求

有的web服务器有鉴权功能,当发起一个请求时,如果在该请求之前还没有登录,会自动重定向到登录页面,登录成功后才会跳转到想要请求的页面。

这时代码应该这样写:

MyHttpClient httpClient = new MyHttpClient("localhost");
//下面是登录请求
httpClient.doPost(loginUrl,"username=xxx&password=yyy");
//因为前面已经登录,下面的url将不会发生重定向。而是返回该url对应页面的本身信息。
String result = httpClient.doGet(url);
System.out.println(result);

6、与cookie有关的请求

有的web应用中,用到了cookie。所谓的cookie,就是希望浏览器操作关闭后,会在浏览器本地客户端机器上记录下一些信息。当下次打开浏览器,操作相关的页面后,这些信息能被带到服务器。我们封装的这个功能对此也支持。具体通过例子说明:

MyHttpClient httpClient = new MyHttpClient("localhost");
//下面的操作,会产生cookie        
httpClient.doPost(url,paras);
//获取本次会话产生的cookie
String cookies  = httpClient.getCookies();

//开启一个新的会话
MyHttpClient otherHttpClient = new MyHttpClient("localhost");
//将上次会话的cookie设置到本次会话中,以便于cookie能带到服务器
otherHttpClient.setCookies(cookies);
//这次请求就会上个会话产生的cookie带到服务器
String result = otherHttpClient.doGet(otherUrl);
System.out.println(result);


三、小结

我们封装的这个httpclient类,可以很方便的完成http请求的一些基本操作。并且对有鉴权控制、cookie功能的网站也能较好的满足。

 

推荐阅读