HttpURLConnection和HttpClient简单上手

× Navigator
  1. 1. 前言
  2. 2. HttpURLConnection
    1. 2.1. 简单GET请求
    2. 2.2. 进行上传文件
  3. 3. HttpClient
    1. 3.1. Maven
    2. 3.2. Gradle
    3. 3.3. 简单的GET请求
    4. 3.4. 简单的POST请求
    5. 3.5. 文件上传
  4. 4. 小结
  5. 5. 参考链接

前言

    最近做项目过程中要搞HTTP请求的时候总是只能用以前写好的URLUtil,略是僵硬,想起之前做安卓有用过okhttp和httpclient,试着在Java里用一用并对比一下他们的效果吧。


HttpURLConnection

    原生Java自带的http请求方式,抽象类URLConnection是表示应用程序和URL之间的通信链接的所有类的超类。 该类的实例可以用于从URL引用的资源中读取和写入。而HttpURLConnection是最常用于进行Http链接的他的子类。
请求方式一般步骤(参考JDK文档):

  1. 通过在URL上调用openConnection方法创建连接对象。
  2. 设置参数和一般请求属性。
  3. 使用connect方法实现与远程对象的实际连接。
  4. 远程对象变得可用。 可以访问头字段和远程对象的内容。

简单GET请求

public String getByConnection(String str) throws IOException {
    //1.创建连接
    URL url = new URL(str);
    HttpURLConnection httpConn = (HttpURLConnection)url.openConnection();
    //2.设置参数
    httpConn.setRequestMethod("GET");       //请求类型
    httpConn.setRequestProperty( "Content-Type", "text/html;charset=UTF-8" );  //请求属性
    httpConn.setConnectTimeout(100000);     //连接超时时间
    httpConn.setReadTimeout(100000);        //读取超时时间
    httpConn.setDoInput(true);              //是否读入
    httpConn.setDoOutput(true);             //是否输出
    httpConn.setUseCaches(true);            //是否使用缓存
    //3.连接
    httpConn.connect();                     //其实会调用所以不必要用connect()
    //4.访问连接内容
    BufferedReader reader = new BufferedReader(new InputStreamReader(httpConn.getInputStream()));
    String line;
    StringBuffer buffer = new StringBuffer();
    while ((line = reader.readLine()) != null) {
        buffer.append(line);
    }
    reader.close();
    httpConn.disconnect();
    return buffer.toString();
}

进行上传文件

之所以不写Post原因是上传文件实际上就是一种特殊的POST,只是比简单的POST要多上不少东西,对于简单的POST可以只是向连接的OutputStream中写入键值对便可以了(跟get没什么区别的话也没太多必要用POST)。

首先由于HttpURLConnection的局限性(他只是一个抽象类,没有什么特别的集成),对于上传文件这类”multipart/form-data”类型的请求类型只能由我们手动拼接Header (我来组成头部!),所以在说如何用HttpURLConnection进行上传文件前先说说上传时的Header:

可见在这用POST上传图片实际上就是模拟表单上传,而这时需要有拼接请求体:
Http Header

  1. 请求体中需要先以”—–一串随机数字(代码中用的是UUID的随机序列)\r\n(\r\n的作用是换行)”来上下分隔。所以在前后都要加上boundary
  2. 然后写入Content-Disposition:form-data;name=”(此处需要与服务器约定)“;filename=”文件名“;
  3. 通过InputStream写入HttpURLConnection的OutputStream中。
  4. 最后以”—–那一串数字–\r\n”结尾。
public String uploadByConnection(String str) throws IOException{
    //1.创建连接
    URL url = new URL(str);
    HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
    //2.设置参数
    String Boundary = UUID.randomUUID().toString();     //请求边界
    httpConn.setRequestMethod("POST");                  //请求类型
    httpConn.setRequestProperty("Charset", "utf-8");    //请求属性
    httpConn.setRequestProperty( "Content-Type", "multipart/form-data; boundary="+Boundary ); //请求属性
    httpConn.setConnectTimeout(100000);     //连接超时时间
    httpConn.setReadTimeout(100000);        //读取超时时间
    httpConn.setDoInput(true);              //是否读入
    httpConn.setDoOutput(true);             //是否输出
    httpConn.setUseCaches(true);            //是否使用缓存
    //3.HTTP请求体
    DataOutputStream out = new DataOutputStream(httpConn.getOutputStream());
    out.writeUTF("Content-Disposition: form-data; name=\"user_upload_icon\";filename=\"foo.jpg\"\r\n\r\n");
    InputStream in = new FileInputStream("src/foo.jpg");
    byte[] b = new byte[1024];
    int l = 0;
    while((l = in.read(b)) != -1) out.write(b,0,l); // 写入文件
    out.writeUTF("\r\n--"+Boundary+"--\r\n");
    out.flush();
    out.close();
    in.close();
    //4.获取响应信息
    BufferedReader reader = new BufferedReader(new InputStreamReader(httpConn.getInputStream()));
    String line;
    StringBuffer buffer = new StringBuffer();
    while ((line = reader.readLine()) != null) {
        buffer.append(line);
    }
    reader.close();
    httpConn.disconnect();
    return buffer.toString();
}

HttpClient

    作为Apache下手开发的工具包,使用起来比JDK自带的更为轻松和简单,实现的功能也更多。
HttpCLient最关键的方法是执行HTTP请求的方法execute。只要把HTTP请求传入,就可以得到HTTP响应。
使用HttpClient请求一个Http请求的步骤为:

  1. 创建一个HttpClient对象
  2. 创建一个Request对象
  3. 使用HttpClient来执行Request请求,得到对方的response
  4. 处理response
  5. 关闭HttpClient

Maven

<dependency>
  <groupId>org.apache.httpcomponents</groupId>
  <artifactId>httpclient</artifactId>
  <version>4.5.6</version>
</dependency>
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpmime</artifactId>
    <version>4.5</version>
</dependency>

Gradle

compile 'org.apache.httpcomponents:httpclient:4.5.6'

简单的GET请求

public String getByClient(String str) throws IOException {
    CloseableHttpClient client = HttpClients.createDefault();       //创建HttpClient对象
    RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(1000).build();   //可以对请求进行各种配置
    HttpGet httpGet = new HttpGet(str);                             //创建Get请求
    httpGet.setConfig(requestConfig);                               //设置配置
    CloseableHttpResponse response = client.execute(httpGet);       //通过Client执行请求
    String result = EntityUtils.toString(response.getEntity());     //处理获得的Http实体
    response.close();                                               //关闭各种资源
    client.close();
    return result;
}

    这绝对是肉眼可见的代码量减少,而且步骤十分清晰。值得一提的是,HttpClient以前的构建方式已经废弃,不能使用了:
HttpClinet client = new HttpClient();

简单的POST请求

    对于Post请求HttpClient巧妙的设计了HttpEntity类,以它来实现Http请求时的请求体,而且可以以多种方式创建,以便实现各种Post请求如表格,文件等,简单Post请求则可以用简单键值对来创建。

public static String postByClient(String str, String phone, String password) throws IOException{
    CloseableHttpClient client = HttpClients.createDefault();       //创建HttpClient对象
    RequestConfig requestConfig = RequestConfig.custom().           //对请求进行各种配置
            setConnectTimeout(1000).setConnectionRequestTimeout(1000)
            .setSocketTimeout(1000).setRedirectsEnabled(true).build();
    List<BasicNameValuePair> list = new ArrayList<BasicNameValuePair>();    //以列表形式创建Post的键值对信息
    list.add(new BasicNameValuePair("phone",phone));
    list.add(new BasicNameValuePair("password", password));
    UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list,"utf-8");   //用列表创建表格编码实体
    HttpPost httpPost = new HttpPost(str);                          //创建Post请求
    httpPost.setConfig(requestConfig);                              //设置配置
    httpPost.setEntity(entity);                                     //设置实体信息
    CloseableHttpResponse response = client.execute(httpPost);      //执行post请求
    String result = EntityUtils.toString(response.getEntity());     //处理获得的Http实体
    response.close();                                               //关闭各种资源
    client.close();
    return result;
}

文件上传

    对于Post请求上传文件可以利用MultipartEntityBuilder来进行Http请求体的创建,利用addPart(key,body)的形式可以对多形式的value进行记入。

public static String uploadByClient(String str) throws IOException{
    CloseableHttpClient client = HttpClients.createDefault();       //创建HttpClient对象
    RequestConfig requestConfig = RequestConfig.custom().           //对请求进行各种配置
            setConnectTimeout(1000).setConnectionRequestTimeout(1000)
            .setSocketTimeout(1000).setRedirectsEnabled(true).build();
    FileBody body = new FileBody(new File("src/foo.jpg"), ContentType.MULTIPART_FORM_DATA);
    HttpEntity entity = MultipartEntityBuilder.create().addPart("user_upload_icon",body).build();   //直接用MultipartEntityBuilder创建HTTP实体
    HttpPost httpPost = new HttpPost(str);                          //创建Post请求
    httpPost.setConfig(requestConfig);                              //设置配置
    httpPost.setEntity(entity);                                     //设置实体信息
    CloseableHttpResponse response = client.execute(httpPost);      //执行post请求
    String result = EntityUtils.toString(response.getEntity());     //处理获得的Http实体
    response.close();                                               //关闭各种资源
    client.close();
    return result;
}

小结

    这次简单的说了一下HttpURLConnection和HttpClinet的get/post请求方式,而且也很明显比较可见HttpClient集成的东西,帮我们做到的东西。当然HttpClient可以做的事远远不止get/post请求,他还有各种强大的功能在背后,他的设计与效果是十分精湛的。可以参考下面的链接来看关于HttpClient的更多用法与解析。
    除了HttpURLConnection和HttpClinet以外,还有许多的优秀网络框架,如okhttp,Volley等,在安卓端开发时备受好评。(而且HttpClient在API 23后都不支持使用了)当然像这样轻量级的框架在做简单请求操作的时候是完全足够的,对于其他的框架以后再看吧。


参考链接

  1. ABOUT HEADER
  2. HTTPCLIENT
  3. HTTPCLIENT TUTORIALS

上一篇
下一篇