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

来源:互联网 发布:淘宝怎么查看旺旺号 编辑:程序博客网 时间:2024/05/17 07:36

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<String, String> 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<String, String> 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=13468857714Post方式请求参数params--->pwd=e10adc3949ba59abbe56e057f20f883e&username=13468857714Post方式请求成功,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网络请求框架。

1 0