概述
在Android开发中网络请求是最常用的操作之一, Android SDK中对HTTP(超文本传输协议)也提供了很好的支持,这里包括两种接口:
- 标准Java接口(java.NET) —-HttpURLConnection,可以实现简单的基于URL请求、响应功能;
- Apache接口(org.appache.http)—-HttpClient,使用起来更方面更强大。
但在android API23
的SDK
中Google
将HttpClient
移除了。Google
建议使用httpURLconnection
进行网络访问操作。
常见请求
HttpURLconnection
是基于http
协议的,支持get
,post
,put
,delete
等各种请求方式,最常用的就是get
和post
,下面针对这两种请求方式进行讲解。
get
请求
get请求可以获取静态页面,也可以把参数放在URL
字串后面,传递给服务端post
请求
post
与get
的不同之处在于post
的参数不是放在URL
字串里面,而是放在http
请求的正文内
构建请求
可以采用如下方式构建请求,当然,这只是构建请求。并没有发起实质的请求呢。
URL url = new URL("http://localhost:8080/TestHttpURLConnectionPro/index.jsp");
URLConnection rulConnection = url.openConnection();
// 此处的urlConnection对象实际上是根据URL的
// 请求协议(此处是http)生成的URLConnection类
// 的子类HttpURLConnection,故此处最好将其转化
// 为HttpURLConnection类型的对象,以便用到
// HttpURLConnection更多的API.如下:
HttpURLConnection httpUrlConnection = (HttpURLConnection) rulConnection;
参数设置
// 设置是否向httpUrlConnection输出,因为这个是post请求,参数要放在
// http正文内,因此需要设为true, 默认情况下是false;
httpUrlConnection.setDoOutput(true);
// 设置是否从httpUrlConnection读入,默认情况下是true;
httpUrlConnection.setDoInput(true);
// Post 请求不能使用缓存
httpUrlConnection.setUseCaches(false);
// 设定传送的内容类型是可序列化的java对象
// (如果不设此项,在传送序列化对象时,当WEB服务默认的不是这种类型时可能抛java.io.EOFException)
httpUrlConnection.setRequestProperty("Content-type", "application/x-java-serialized-object");
// 设定请求的方法为"POST",默认是GET
httpUrlConnection.setRequestMethod("POST");
// 设置好所有的参数后就可以连接了
httpUrlConnection.connect();
设置好所有的参数后可以调用 httpUrlConnection.connect
方法进()行连接 ,也可以直接调用 getOutputStream()
进行连接,这个方法中会自动调用 connect()
方法进行连接。
OutputStream outStrm = httpUrlConnection.getOutputStream();
进行连接。
**注意:**但实际上到这里,只是建立了一个与服务器的tcp
连接,并没有实际发送http请求。
###发起请求
上面我们说了,不管是 getOutputStream()
,还是 connect()
方法,最后都没有真正的发起请求。getInputStream()
才是实际发送请求的地方。但是这个方法有个问题,如果该服务不管用或服务拒绝,它就会抛出 FileNotFoundException
的异常,这非常的不友好,且也不好定位错误。
1 // 现在通过输出流对象构建对象输出流对象,以实现输出可序列化的对象。
2 ObjectOutputStream objOutputStrm = new ObjectOutputStream(outStrm);
3
4 // 向对象输出流写出数据,这些数据将存到内存缓冲区中
5 objOutputStrm.writeObject(new String("我是测试数据"));
6
7 // 刷新对象输出流,将任何字节都写入潜在的流中(些处为ObjectOutputStream)
8 objOutputStm.flush();
9
10 // 关闭流对象。此时,不能再向对象输出流写入任何数据,先前写入的数据存在于内存缓冲区中,
11 // 在调用下边的getInputStream()函数时才把准备好的http请求正式发送到服务器
12 objOutputStm.close();
13
14 // 调用HttpURLConnection连接对象的getInputStream()函数,
15 // 将内存缓冲区中封装好的完整的HTTP请求电文发送到服务端。
16 InputStream inStrm = httpConn.getInputStream(); // <===注意,实际发送请求的代码段就在这里
17
18 // 上边的httpConn.getInputStream()方法已调用,本次HTTP请求已结束,下边向对象输出流的输出已无意义,
19 // 既使对象输出流没有调用close()方法,下边的操作也不会向对象输出流写入任何数据.
20 // 因此,要重新发送数据时需要重新创建连接、重新设参数、重新创建流对象、重新写数据、
所以我们需要在 httpConn.getInputStream()
方法前面加一段代码,判断下网络连接是否通畅,是否有问题。当然我这个只是示例,仅仅简单的做了判断。你可以根据你的需求添加详细的业务逻辑。
int responseCode = urlConnection.getResponseCode();
if (responseCode != 200) {
Logger.e("网络连接失败 responseCode:"+responseCode);
return null;
}
httpConn.getInputStream()
###一次完整请求的最佳实践
private static String doPost(String data) {
try {
HttpURLConnection urlConnection = (HttpURLConnection) (new URL("http://api.faceid.com/faceid/v1/sdk/authm")).openConnection();
urlConnection.setConnectTimeout(5000);
urlConnection.setReadTimeout(5000);
urlConnection.setRequestMethod("POST");
urlConnection.setRequestProperty("Content-type", "text/plain");
urlConnection.setDoOutput(true);
BufferedOutputStream bos = new BufferedOutputStream(urlConnection.getOutputStream());
bos.write(data.getBytes());
bos.close();
int responseCode = urlConnection.getResponseCode();
if (responseCode != 200) {
Logger.e("网络连接失败 responseCode:"+responseCode);
return null;
}
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
StringBuilder stringBuilder = new StringBuilder();
String tmp;
while ((tmp = bufferedReader.readLine()) != null) {
stringBuilder.append(tmp);
}
bufferedReader.close();
urlConnection.disconnect();
return stringBuilder.toString();
} catch (IOException var6) {
var6.printStackTrace();
return null;
}
}
总结
- 首先确实如 HttpURLConnection用法详解 文章中所说,各参数的设置顺序、时机挺重要的。
- 记得在实际发起网络请求之前,判断网络状况。不然只会给你抛出一个异常,实在不是一个友好的请求方式。
- http请求实际上由两部分组成,
- 一个是http头,所有关于此次http请求的配置都在http头里面定义,也就是 connect() 方法调用之前的一些配置。 connect()函数会根据
HttpURLConnection
对象的配置值生成http
头部 - 一个是正文
content
,也就是请求体
- 一个是http头,所有关于此次http请求的配置都在http头里面定义,也就是 connect() 方法调用之前的一些配置。 connect()函数会根据
###参考文档
这篇 HttpURLConnection用法详解 非常详细的介绍了应该怎样使用HttpURLConnection
发起一次网络请求 。还对后台如何开发http 请求做了比较深入的介绍。