android 网络请求底层分析,Java Http网络请求HttpURLConnection应用之【Android网络请求框架底层剖析】...

URLConnection是个抽象类,它有两个直接子类分别是HttpURLConnection和JarURLConnection。另外一个重要的类是URL,通常URL可以通过传给构造器一个String类型的参数来生成一个指向特定地址的URL实例。

每个 HttpURLConnection 实例都可用于生成单个请求,但是其他实例可以透明地共享连接到 HTTP 服务器的基础网络。请求后在 HttpURLConnection 的 InputStream 或 OutputStream 上调用 close() 方法可以释放与此实例关联的网络资源,但对共享的持久连接没有任何影响。如果在调用 disconnect() 时持久连接空闲,则可能关闭基础套接字。

需求,发起一个Post请求,并携带参数给服务器,服务器返回Json数据

代码实现

import java.io.*;

import java.net.HttpURLConnection;

import java.net.MalformedURLException;

import java.net.URL;

import java.net.URLEncoder;

import java.util.HashMap;

/**

* Created by yuandl on 2016-10-18.

* HttpURLConnection测试

*/

public class URLConnectionTest {

public static void main(String[] args) {

String url = "http://10.58.178.72/intco/mobi/member/login";

HashMap params = new HashMap<>();

params.put("username", "13468857714");

params.put("pwd", MD5.md5("123456").toLowerCase());

requestPost(url, params);

}

/**

* Post请求

*

* @param httpUrl

* @param paramsMap

*/

private static void requestPost(String httpUrl, HashMap paramsMap) {

try {

String baseUrl = httpUrl;

//合成参数

StringBuilder tempParams = new StringBuilder();

int pos = 0;

for (String key : paramsMap.keySet()) {

if (pos > 0) {

tempParams.append("&");

}

tempParams.append(String.format("%s=%s", key, URLEncoder.encode(paramsMap.get(key), "utf-8")));

pos++;

}

String params = tempParams.toString();

System.out.println("Post方式请求地址httpUrl--->" + params);

System.out.println("Post方式请求参数params--->" + params);

// 请求的参数转换为byte数组

byte[] postData = params.getBytes();

// 新建一个URL对象

URL url = new URL(baseUrl);

// 打开一个HttpURLConnection连接

HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();

// 设置连接超时时间

urlConn.setConnectTimeout(5 * 1000);

//设置从主机读取数据超时

urlConn.setReadTimeout(5 * 1000);

// Post请求必须设置允许输出 默认false

urlConn.setDoOutput(true);

//设置请求允许输入 默认是true

urlConn.setDoInput(true);

// Post请求不能使用缓存

urlConn.setUseCaches(false);

// 设置为Post请求

urlConn.setRequestMethod("POST");

//设置本次连接是否自动处理重定向

urlConn.setInstanceFollowRedirects(true);

// 配置请求Content-Type

urlConn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

// 开始连接

urlConn.connect();

// 发送请求参数

DataOutputStream dos = new DataOutputStream(urlConn.getOutputStream());

dos.write(postData);

dos.flush();

dos.close();

// 判断请求是否成功

if (urlConn.getResponseCode() == 200) {

// 获取返回的数据

String result = streamToString(urlConn.getInputStream());

System.out.println("Post方式请求成功,result--->" + result);

} else {

System.out.println("Post方式请求失败");

}

// 关闭连接

urlConn.disconnect();

} catch (Exception e) {

e.printStackTrace();

}

}

/**

* 将输入流转换成字符串

*

* @param is 从网络获取的输入流

* @return

*/

public static String streamToString(InputStream is) {

try {

ByteArrayOutputStream baos = new ByteArrayOutputStream();

byte[] buffer = new byte[1024];

int len = 0;

while ((len = is.read(buffer)) != -1) {

baos.write(buffer, 0, len);

}

baos.close();

is.close();

byte[] byteArray = baos.toByteArray();

return new String(byteArray);

} catch (Exception e) {

e.printStackTrace();

return null;

}

}

}

打印结果

Post方式请求地址httpUrl--->pwd=e10adc3949ba59abbe56e057f20f883e&username=13468857714

Post方式请求参数params--->pwd=e10adc3949ba59abbe56e057f20f883e&username=13468857714

Post方式请求成功,result--->{"status":1,"data":{"mId":"426e743224db4ecb8313e069982a7496","mName":"*东亮","pwd":"f241426298243cb7f6f97da58749ffb386c1457d","sex":"1","mobile":"13468857714","authentication":"0","personal":"0","isMain":"1","parentId":"0","newOrold":"1","imgurl":"http://10.58.178.72/intco/upload/img/member/portrait/2016/10/9331f754fbb742d99f6e61dcee0fe61d.jpg","state":"1","rongcloud_token":"1XHoYMAzlXidThqzyftV8at+qlfSNm8M8gqvzen0AUEV4lvsXAvmBJF0GQBkh5JP1I3XDUvd60sWEglC4+KRsnv5d+pcovzErw8ekgl7y6fM3gYaOuFDcqN0iaV2F2PAOM4jDTjH9M8="},"msg":"登录成功!"}

总结

HttpURLConnection的connect()函数,实际上只是建立了一个与服务器的tcp连接,并没有实际发送http请求。 无论是post还是get,http请求实际上直到HttpURLConnection的getInputStream()这个函数里面才正式发送出去。

在用POST方式发送URL请求时,URL请求参数的设定顺序是重中之重, 对connection对象的一切配置(那一堆set函数) 都必须要在connect()函数执行之前完成。而对outputStream的写操作,又必须要在inputStream的读操作之前。 这些顺序实际上是由http请求的格式决定的。

http请求实际上由两部分组成, 一个是http头,所有关于此次http请求的配置都在http头里面定义, 一个是正文content。 connect()函数会根据HttpURLConnection对象的配置值生成http头部信息,因此在调用connect函数之前, 就必须把所有的配置准备好。

在http头后面紧跟着的是http请求的正文,正文的内容是通过outputStream流写入的,实际上outputStream不是一个网络流,充其量是个字符串流,往里面写入的东西不会立即发送到网络, 而是存在于内存缓冲区中,待outputStream流关闭时,根据输入的内容生成http正文。 至此,http请求的东西已经全部准备就绪。在getInputStream()函数调用的时候,就会把准备好的http请求 正式发送到服务器了,然后返回一个输入流,用于读取服务器对于此次http请求的返回信息。由于http 请求在getInputStream的时候已经发送出去了(包括http头和正文),因此在getInputStream()函数 之后对connection对象进行设置(对http头的信息进行修改)或者写入outputStream(对正文进行修改) 都是没有意义的了,执行这些操作会导致异常的发生。

分析

HttpURLConnection是Java层提供的标准网络请求工具类,可以实现各种功能。通过以上的代码和返回的请求结果可以知道,我们知道其实在Android中无论什么网络请求框架,最底层也是这样去实现的。我们可以在这个上面继续封装,不断完善就可以成为一个轻量级的Android网络请求框架。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值