初识http

无论是后端开发还是前端开发,http都是一门必修课. 对于Android开发来说,Retrofit + OkHttp的方案已经成了官方标配.

但本文的主角不是它们,而是HttpURLConnection.但是HttpURLConnection跟OkHttp也有着密切的关系,在Android 4.4之后,是基于OkHttp实现的.

源码分析开始:

1
2
3
4
5
6
7
8
9
10
11
12
13
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Hashtable;
import java.util.Date;
import java.util.StringTokenizer;
import java.util.Collections;
import java.util.Map;
import java.util.List;
import java.security.Permission;
import java.security.AccessController;
import sun.security.util.SecurityConstants;
import sun.net.www.MessageHeader;

所以要搞清楚这个类,你需要有Java I/O以及集合的基础知识.再者,你也需要了解http协议的一些基础知识.mozilla基金会下的这个http的几篇文章,会让你对http协议有个明确的概念.如果想要进行更近一步的了解,这本HTTP权威指南会进一步打开你的视野.HTTP3协议已然发布的当下,去拥抱H2也是不可少的了,这本HTTP/2基础教程,会给出一些你想要的答案.

回过来继续看源码:

![截屏2020-12-03 下午8.23.10](/Users/jinyulei/Desktop/截屏2020-12-03 下午8.23.10.png)

HTTP状态码的定义,2XX,3XX,4XX,以及5XX系列.

![截屏2020-12-03 下午8.30.17](/Users/jinyulei/Desktop/截屏2020-12-03 下午8.30.17.png)

再倒着往上看,看到的是合法的HTTP方法,依次是 “GET”,”POST”,”HEAD”,”OPTIONS”,”PUT”,”DELETE”,”TRACE”.

对于熟悉RESTFUL API的开发者来说,最为熟悉的可能是GET,POST,DELETE,PUT,以及跨域时会遇到到的OPTIONS.

然后是一个是否要重定向的标志位:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 /* do we automatically follow redirects? The default is true. */
private static boolean followRedirects = true;


/**
* If {@code true}, the protocol will automatically follow redirects.
* If {@code false}, the protocol will not automatically follow
* redirects.
* <p>
* This field is set by the {@code setInstanceFollowRedirects}
* method. Its value is returned by the {@code getInstanceFollowRedirects}
* method.
* <p>
* Its default value is based on the value of the static followRedirects
* at HttpURLConnection construction time.
*
* @see java.net.HttpURLConnection#setInstanceFollowRedirects(boolean)
* @see java.net.HttpURLConnection#getInstanceFollowRedirects()
* @see java.net.HttpURLConnection#setFollowRedirects(boolean)
*/

protected boolean instanceFollowRedirects = followRedirects;

响应状态码以及响应消息体:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* An {@code int} representing the three digit HTTP Status-Code.
* <ul>
* <li> 1xx: Informational
* <li> 2xx: Success
* <li> 3xx: Redirection
* <li> 4xx: Client Error
* <li> 5xx: Server Error
* </ul>
*/
protected int responseCode = -1;

/**
* The HTTP response message.
*/
protected String responseMessage = null;

默认块大小,

1
private static final int DEFAULT_CHUNK_SIZE = 4096;

streaming 模式下的内容长度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
* The fixed content-length when using fixed-length streaming mode.
* A value of {@code -1} means fixed-length streaming mode is disabled
* for output.
*
* <P> <B>NOTE:</B> {@link #fixedContentLengthLong} is recommended instead
* of this field, as it allows larger content lengths to be set.
*
* @since 1.5
*/
protected int fixedContentLength = -1;

/**
* The fixed content-length when using fixed-length streaming mode.
* A value of {@code -1} means fixed-length streaming mode is disabled
* for output.
*
* @since 1.7
*/
protected long fixedContentLengthLong = -1;

/**
* The chunk-length when using chunked encoding streaming mode for output.
* A value of {@code -1} means chunked encoding is disabled for output.
* @since 1.5
*/
protected int chunkLength = -1;

以及默认为”GET”的method字段.

然后再从头往下看:

URLCONNECTION并不支持HTTP2.

然后姿势很重要,我们需要遵照以下方法.

通过调用URL的openConnection()的获取一个URLConnection并将其转换为HttpURLConnection.

准备请求,请求的主要参数是它的URI.请求头中包含了认证、内容类型以及cookie.请求体是可选的,如果请求包含请求体,setDoOutPut()就必须设置为true.传输数据以向getOutputStream()返回的stream的方式完成.

读取响应体.响应体的的首部,通常包含了响应体的内容类型和大小.修改日期以及会话的cookie.通过经由getInputStream()返回的stream,能够读取到响应体.如果响应没有body,那边方法返回的就是空流.

断开连接,一旦响应体读取完了,HttpURLConnection就应该通过调用Disconnecting来释放由连接所持有的资源,从而它们能够被关闭或重用.