android网络请求全面解析
来源:互联网 发布:matlab 符号矩阵 编辑:程序博客网 时间:2024/06/05 16:13
android中发起网络请求主要的有get和post两种:
get:
public String get(String url) { HttpURLConnection conn = null; try { URL mURL = new URL(url); conn = (HttpURLConnection) mURL.openConnection(); conn.setRequestMethod("GET"); conn.setReadTimeout(5000); conn.setConnectTimeout(10000); //类似于Content-Type这种约定俗成的,还可以包括一些自定义的例如CUSTOM_OS, //需要和服务器约定好 conn.setRequestProperty("Content-Type", "text/xml"); conn.addRequestProperty("CUSTOM_OS", "android"); int responseCode = conn.getResponseCode(); if (responseCode == 200) { InputStream is = conn.getInputStream(); ByteArrayOutputStream os = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len = -1; while ((len = is.read(buffer)) != -1) { os.write(buffer, 0, len); } is.close(); String response = os.toString(); os.close(); return response; } else { throw new NetworkErrorException("response status is "+responseCode); } } catch (Exception e) { e.printStackTrace(); } finally { if (conn != null) { conn.disconnect(); } } return null; }
post:
public String post(String url, String content) { HttpURLConnection conn = null; try { URL mURL = new URL(url); conn = (HttpURLConnection) mURL.openConnection(); conn.setRequestMethod("POST"); conn.setReadTimeout(5000); conn.setConnectTimeout(10000); conn.setDoOutput(true);// 设置此方法,允许向服务器输出内容,必须在connect之前调用 String data = content; OutputStream out = conn.getOutputStream(); out.write(data.getBytes()); out.flush(); out.close(); int responseCode = conn.getResponseCode(); if (responseCode == 200) { InputStream is = conn.getInputStream(); ByteArrayOutputStream os = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len = -1; while ((len = is.read(buffer)) != -1) { os.write(buffer, 0, len); } is.close(); String response = os.toString(); os.close(); return response; } else { throw new NetworkErrorException("response status is "+responseCode); } } catch (Exception e) { e.printStackTrace(); } finally { if (conn != null) { conn.disconnect(); } } return null; }
首先URL的openConnection()会返回一个URLConnection的实例对象,这个对象可以对服务器读写,openConnection()方法是调用的URLStreamHandler实例对象的openConnection(),
在SDK中的URLConnection有坑,这个类中的方法很多都是空的实现,真正的源码的JDK里面,所以下面讨论的都是JDK中的类,首先URL的openConnection()会返回一个URLConnection的实例对象,这个对象可以对服务器读写,其中URL的openConnection()会辗转调用到URLStreamHandler实例对象的openConnection(),下图:
其中(1)(2)均在sun.net.www.protocol.http包中(Handler HttpURLConnection),这个包JDK中没有,其他均在java.net包中,到这里都比较简单,平常基本使用都可以了,但是我们除了要知其然还要知其所以然,很有必要继续深究下其中的原理以及其他的用法。
先从URL类开始,这个类主要是解析出主机名,端口号,协议等信息,
其中的协议有http,ftp,ftp适合传送大文件,http适合传送网页等数据,平时我们的网址还有接口都是http协议的。
然后调用openConnection或openStream打开链接,不同点是openStream会调用先openConnection返回一个URLConnection对象后在调用改对象的getInputStream,这里就是打开链接后直接获取输入流,如果我们直接调用openConnection可能后面还会写入一些东西然后在获取输入流,典型的就是post请求的设置header和写出参数。
get和post最大的区别就是有没有通过OutputStream 被虚拟机包装到body中向服务器传递数据,先分析下getOutputStream的过程
public synchronized OutputStream getOutputStream() throws IOException { try { if (!doOutput) {//通过setDoInput设置 throw new ProtocolException("cannot write to a URLConnection" + " if doOutput=false - call setDoOutput(true)"); } if (method.equals("GET")) {//请求方法为get时会被置为post method = "POST"; // Backward compatibility } if (!"POST".equals(method) && !"PUT".equals(method) && "http".equals(url.getProtocol())) {//必须为post或put,协议为http throw new ProtocolException("HTTP method " + method + " doesn't support output"); } // if there's already an input stream open, throw an exception if (inputStream != null) { throw new ProtocolException("Cannot write output after reading input."); } if (!checkReuseConnection()) connect();//如果没有connect会调用connect() boolean expectContinue = false; /* *是否设置了Expect: 100-Continue *如果设置了会先询问服务器是否处理post数据 */ String expects = requests.findValue("Expect"); if ("100-Continue".equalsIgnoreCase(expects)) { http.setIgnoreContinue(false); expectContinue = true; } if (streaming() && strOutputStream == null) { /* *将没有设置的header设置默认置然后调用httpclient的writeRequests *向输出流写出数据 */ writeRequests(); } if (expectContinue) { //如果设置了Expect: 100-Continue,检查服务器返回的code是否允许发送post请求 expect100Continue(); } ps = (PrintStream) http.getOutputStream();//调用httpclient的getOutputStream方法 if (streaming()) { if (strOutputStream == null) { if (chunkLength != -1) { /* chunked */ strOutputStream = new StreamingOutputStream( new ChunkedOutputStream(ps, chunkLength), -1L); } else { /* must be fixed content length */ long length = 0L; if (fixedContentLengthLong != -1) { length = fixedContentLengthLong; } else if (fixedContentLength != -1) { length = fixedContentLength; } strOutputStream = new StreamingOutputStream(ps, length); } } return strOutputStream; } else { if (poster == null) { poster = new PosterOutputStream(); } return poster; } } //部分删减 }
HttpURLConnecion的getOutputStream会调用HttpClient的getOutputStream,看一下HttpClient的getOutputStream方法
public OutputStream getOutputStream() { return serverOutput;}
直接返回了serverOutput,这个变量在openServer(String server, int port)中赋值,openServer方法有两个地方会调用,一个是HttpClient初始化时(调用父类NetworkClient 的构造方法),一个是会在parseHTTP(MessageHeader responses, ProgressSource pi, HttpURLConnection httpuc)中调用,而这个方法会在HttpURLConnecion中getInputStream中调用。
这样获得了输出流,这时只是把数据写入到内存中,并没有发送给服务器,发送过程在HttpURLConnection的getInputStream方法中调用strOutputStream.close ()写入到流中发送给服务器。
不过到这肯定还有很多疑问,不是先调用的getOutputStream,难道是在这里面就初始化了一个HttpClient对象?确实是,在HttpURLConnecion的getOutputStream和getInputStream中都会在没有建立连接时调用connect(),它又调用了plainConnect(),在这里面new了一个HttpClient 对象,这样就调用到了前面提到的openServer(),它里面建立了一个socket连接(对使用的是socket连接)。
现在就比较清楚了,post请求比get请求多了一步getOutputStream,但不管什么请求都是先调用connect(),建立一个socket连接,如果是post还会返回一个outputStream对象用来向服务器发送数据,然后getOutputStream和getInputStream中会调用writeRequests()方法,这个方法会设置一些默认的请求头参数,然后里面调用HttpClient的writeRequests()方法将这些参数发送给服务器,之后post会通过outputStream对象发送数据,这些数据就是接口的参数,发送完在getInputStream()方法中将缓存中数据发送到服务器,等待服务器返回,最后关闭连接一次请求就完成了。
- android网络请求全面解析
- Android中解析网络请求的URL
- android url网络请求+json解析
- Android的网络请求方式解析
- Android okHttp网络请求之Json解析
- android launcher 全面解析
- android viewgroup全面解析
- Android Bitmap 全面解析
- android launcher 全面解析
- android launcher 全面解析
- android launcher 全面解析
- Android Bitmap 全面解析
- Android Intent全面解析
- Android Bitmap 全面解析
- Android动画全面解析
- Android Activity全面解析
- Android Activity全面解析
- Android Service全面解析
- php基础03_函数
- 通过acl限制vlan间通信
- 保护接地、功能性接地、和等电位接地
- 数据库操作:MYSQL与MFC连接(二)
- nodejs学习三
- android网络请求全面解析
- CoordinatorLayout的简单使用
- 用Spring Boot颠覆Java应用开发
- 利用JQuery操作form表单,例如:text,radis,checkbox,file等等之类的
- 2016-12-26-RBAC模型
- 数据库课程设计(实验报告管理系统)
- 霍夫曼编码
- 小扎-我的成长之路
- jvm.dll,启动eclipse时弹出Failed to load the JNI shared library