先瞄瞄UML类图
在Volley中真正的网络请求是由HttpStack定义的,这是一个接口,它唯一的一个方法就是执行网路请求获取响应。而HttpClientStack和HurlStack是该接口的实现类,对应不同的网络请求的底层实现,HttpClientStack是基于HttpClient的,HurlStack是基于HttpURLConnection的。
先看看这个父接口(HttpStack)
源码解读绝招一:看父类,接口,这样你才知道这个类是干啥的,应该有什么行为
/**
* Volley中真正去执行联网的类,返回的信息封装成HttpResponse
*/
public interface HttpStack {
/**
* 真正去执行联网的方法
*/
public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
throws IOException, AuthFailureError;
}
Volley本来是支持HttpURLConnection,还有HttpClient的,当然处于现在这个年代,HttpClient被废弃了,所以只看HttpURLConnection的封装
另外说一点Volley中的Request,从字面理解上是请求,但是其实不是一个真正的网络请求,个人理解为是对真正的网络请求的各个属性的描述。
HttpStack是真正的网络请求,Request则是封装了超时时间、请求方式、参数、url等网络请求所必须的参数。通过变换不同的属性参数(最基本的如请求方式GET POST),可以获取不同的网络请求。
OK,现在在说下我对于HttpClientStack和HurlStack的理解,二者的工作思路是这样的:
1. 首先从Volley的Request内获取各个属性、如超时间、请求方式、参数和url
2.创建网络请求,HttpClientStack是创建HttpClient ,HurlStack是创建HttpURLConnection
3.对网络请求设置各个属性参数
4.定义执行网路请求的方法,并获取响应,将响应返回出去
上面说的是思路,现在看一下源码细节是怎么写的,一些得从performRequest开始
源码细节performRequest
@Override
public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
throws IOException, AuthFailureError {
String url = request.getUrl();
HashMap<String, String> map = new HashMap<String, String>();
map.putAll(request.getHeaders());
map.putAll(additionalHeaders);
if (mUrlRewriter != null) {
String rewritten = mUrlRewriter.rewriteUrl(url);
if (rewritten == null) {
throw new IOException("URL blocked by rewriter: " + url);
}
url = rewritten;
}
URL parsedUrl = new URL(url);
//1.得到一个HttpURLConnection
HttpURLConnection connection = openConnection(parsedUrl, request);
//2.设置响应头
for (String headerName : map.keySet()) {
connection.addRequestProperty(headerName, map.get(headerName));
}
//3.设置请求方式
setConnectionParametersForRequest(connection, request);
//4.响应的协议版本
ProtocolVersion protocolVersion = new ProtocolVersion("HTTP", 1, 1);
//5.获取状态码
int responseCode = connection.getResponseCode();
if (responseCode == -1) {
// -1 is returned by getResponseCode() if the response code could not be retrieved.
// Signal to the caller that something was wrong with the connection.
throw new IOException("Could not retrieve response code from HttpUrlConnection.");
}
//6.根据链接获取响应的状态码响应信息
StatusLine responseStatus = new BasicStatusLine(protocolVersion,
connection.getResponseCode(), connection.getResponseMessage());
//创建响应
BasicHttpResponse response = new BasicHttpResponse(responseStatus);
//给响应设置响应体,响应体来自于链接
response.setEntity(entityFromConnection(connection));
//将得到的头信息赋值给实体类(BasicHttpResponse)
for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {
if (header.getKey() != null) {
Header h = new BasicHeader(header.getKey(), header.getValue().get(0));
response.addHeader(h);
}
}
return response;
}
看传入参数Request,里面有设置了很多http的属性,如超时,是否缓存,还有一个参数设置头信息
再看看其中几个重要方法
- openConnection
- setConnectionParametersForRequest 设置请求方式
- entityFromConnection
openConnection封装细节
/**
* 设置HttpURLConnection 一些参数以及支持https
* @param url
* @return an open connection
* @throws IOException
*/
private HttpURLConnection openConnection(URL url, Request<?> request) throws IOException {
HttpURLConnection connection = createConnection(url);
int timeoutMs = request.getTimeoutMs();
connection.setConnectTimeout(timeoutMs);
connection.setReadTimeout(timeoutMs);
connection.setUseCaches(false);
connection.setDoInput(true);
// use caller-provided custom SslSocketFactory, if any, for HTTPS
if ("https".equals(url.getProtocol()) && mSslSocketFactory != null) {
((HttpsURLConnection)connection).setSSLSocketFactory(mSslSocketFactory);
}
return connection;
}
没啥好说的就是创建了HttpURLConnection,设置一些属性
entityFromConnection封装细节
/**
* 将connection得到的信息封装成实体(BasicHttpEntity)返回
* @param connection
* @return
*/
private static HttpEntity entityFromConnection(HttpURLConnection connection) {
BasicHttpEntity entity = new BasicHttpEntity();
InputStream inputStream;
try {
inputStream = connection.getInputStream();
} catch (IOException ioe) {
inputStream = connection.getErrorStream();
}
entity.setContent(inputStream);
entity.setContentLength(connection.getContentLength());
entity.setContentEncoding(connection.getContentEncoding());
entity.setContentType(connection.getContentType());
return entity;
}
这里就是从HttpURLConnection获取接口信息,封装成HttpEntity,返回给调用者BasicNetWork
Volley的真正的网络请求就是这些了,注意这里是定义网络请求和网络请求的方法,但是调用执行网络请求其实是在NetWork接口及其实现类BasicNetwork内。
如果对于HttpURLConnection 不太了解,或者忘记的差不对了可以看看我前面文章