Java 中提供了Http 网络请求的API,即HttpURLConnection,在Android 中,许多网络请求框架也是对HttpURLConnection 的封装处理。这里以实例的方式介绍一下HttpURLConnection 的常见用法。
1. GET 请求
GET 请求可以说是http 请求中最常用的了,那么用HttpURLConnection 要怎么实现呢,可见下面代码:
@NotNull
public String doGet() {
try {
URL requestUrl = new URL(url); // url 是请求地址
HttpURLConnection connection = (HttpURLConnection) requestUrl.openConnection(); // 创建HttpURLConnection 实例
connection.setConnectTimeout(10000); // 设置连接超时时间,单位 ms
connection.setReadTimeout(15000); // 设置读取返回值的超时时间
connection.setInstanceFollowRedirects(false); // 不自动跟随重定向
connection.setRequestProperty("Cookie", cookie); // 设置cookie,其实就是请求头中的一个字段值
if (headers != null) { // headers 是一个key 和 value 均为String 的map,下面代码是批量设置请求头的字段值
headers.forEach(connection::setRequestProperty);
}
InputStream inputStream = connection.getInputStream(); // 获取输入流,此时会进行网络连接,并以流的形式返回结果
connection.disconnect(); // 关闭连接
return readStreamToString(inputStream); // readStreamToString 是一个自己写的将流读成字符串的方法
} catch (IOException e) {
e.printStackTrace();
}
return "";
}
因为是GET 请求,所以请求参数可以放在url 中。
2. POST 请求
POST 和 GET 请求的区别这里不再赘述,使用POST 请求和GET 请求有一些不同,如下例
@NotNull
public String doPost() {
try {
URL requestUrl = new URL(url);
HttpURLConnection connection = (HttpURLConnection) requestUrl.openConnection();
connection.setRequestMethod("POST"); // 需要设置请求方法,默认是GET
connection.setDoInput(true); // 设置是否从httpUrlConnection读入,默认情况下是true
connection.setDoOutput(true); // POST 要设置为true,默认为false
connection.setUseCaches(false); // POST 请求不使用缓存
connection.setRequestProperty("Connection", "Keep-Alive");
connection.setRequestProperty("Cookie", cookie);
if (headers != null) { // 设置请求头
headers.forEach(connection::setRequestProperty);
}
String paramStr = JSON.toJSONString(params); // params 是一个key 为String,value 为Object 的map,使用框架将其转为json串
OutputStream os = connection.getOutputStream(); // 下面这一段代码是通过向HttpURLConnection 写入流的方式设置请求参数
os.write(paramStr.getBytes());
os.flush();
os.close();
connection.disconnect();
return readStreamToString(connection.getInputStream());
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
3. 上传文件
在post请求传递参数时知道,可以从连接中得到一个输出流,输出流可以向服务器写数据。同理,可以使用这个输出流将文件写到服务器。
public String uploadFile(String filePath) {
try {
URL requestUrl = new URL(url);
HttpURLConnection connection = (HttpURLConnection) requestUrl.openConnection();
connection.setRequestMethod("POST");
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setUseCaches(false);
connection.setRequestProperty("Content-Type", "file/*"); //设置数据类型
OutputStream outputStream = connection.getOutputStream();
FileInputStream fileInputStream = new FileInputStream(filePath); //把文件封装成一个流
int length;
byte[] bytes = new byte[1024];
while ((length = fileInputStream.read(bytes)) != -1){
outputStream.write(bytes,0,length); //写的具体操作
}
fileInputStream.close();
outputStream.close();
return readStreamToString(connection.getInputStream());
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
可见,上传文件其实和POST 请求很类似,只是设置请求Header 的 “Content-Type” 有所不同。
注意:
1)HttpURLConnection的connect() 函数,实际上只是建立了一个与服务器的tcp 连接,并没有实际发送http请求。 无论是POST 还是GET,http请求实际上直到HttpURLConnection的getInputStream() 这个函数里面才正式发送出去。
2)在用POST方式发送URL请求时,URL请求参数的设定顺序是重中之重,对connection对象的一切配置(那一堆set函数)都必须要在connect() 函数执行之前完成。而对outputStream的写操作,又必须要在inputStream的读操作之前。这些顺序实际上是由http请求的格式决定的。如果inputStream读操作在outputStream的写操作之前,会抛出异常: java.net.ProtocolException: Cannot write output after reading input.......
3)http请求实际上由两部分组成,一个是http头,所有关于此次http 请求的配置都在http 头里面定义,一个是正文content。 connect() 函数会根据HttpURLConnection 对象的配置值生成http 头部信息,因此在调用connect 函数之前, 就必须把所有的配置准备好。
4)在http头后面紧跟着的是http请求的正文,正文的内容是通过outputStream流写入的,实际上outputStream不是一个网络流,充其量是个字符串流,往里面写入的东西不会立即发送到网络,而是存在于内存缓冲区中,待outputStream流关闭时,根据输入的内容生成http 正文。至此,http请求的东西已经全部准备就绪。在getInputStream() 函数调用的时候,就会把准备好的http请求正式发送到服务器了,然后返回一个输入流,用于读取服务器对于此次http请求的返回信息。由于http 请求在getInputStream的时候已经发送出去了(包括http头和正文),因此在getInputStream() 函数之后对connection 对象进行设置(对http头的信息进行修改)或者写入outputStream(对正文进行修改)都是没有意义的了,执行这些操作会导致异常的发生。
网友评论