前言
最近做项目过程中要搞HTTP请求的时候总是只能用以前写好的URLUtil,略是僵硬,想起之前做安卓有用过okhttp和httpclient,试着在Java里用一用并对比一下他们的效果吧。
HttpURLConnection
原生Java自带的http请求方式,抽象类URLConnection是表示应用程序和URL之间的通信链接的所有类的超类。 该类的实例可以用于从URL引用的资源中读取和写入。而HttpURLConnection是最常用于进行Http链接的他的子类。
请求方式一般步骤(参考JDK文档):
- 通过在URL上调用openConnection方法创建连接对象。
- 设置参数和一般请求属性。
- 使用connect方法实现与远程对象的实际连接。
- 远程对象变得可用。 可以访问头字段和远程对象的内容。
简单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上传图片实际上就是模拟表单上传,而这时需要有拼接请求体:
- 请求体中需要先以”—–一串随机数字(代码中用的是UUID的随机序列)\r\n(\r\n的作用是换行)”来上下分隔。所以在前后都要加上boundary
- 然后写入Content-Disposition:form-data;name=”(此处需要与服务器约定)“;filename=”文件名“;
- 通过InputStream写入HttpURLConnection的OutputStream中。
- 最后以”—–那一串数字–\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请求的步骤为:
- 创建一个HttpClient对象
- 创建一个Request对象
- 使用HttpClient来执行Request请求,得到对方的response
- 处理response
- 关闭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后都不支持使用了)当然像这样轻量级的框架在做简单请求操作的时候是完全足够的,对于其他的框架以后再看吧。