您的位置:首页 > 理论基础 > 计算机网络

Volley框架的基本解读(四)

2016-05-24 16:26 471 查看
废话不多说,放上Volley框架的基本解读(三)的链接,我们继续往下看,先来看看网络执行类HttpStack的源码:

/**
* An HTTP stack abstraction.
*/
public interface HttpStack {
/**
* Performs an HTTP request with the given parameters.
*
* <p>A GET request is sent if request.getPostBody() == null. A POST request is sent otherwise,
* and the Content-Type header is set to request.getPostBodyContentType().</p>
*
* @param request the request to perform
* @param additionalHeaders additional headers to be sent together with
*         {@link Request#getHeaders()}
* @return the HTTP response
*
* 真正的网络请求
*/
public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
throws IOException, AuthFailureError;

}


这是一个接口,里面有一个与Network接口同名,但又不一样的方法。

具体实现是由Volley.newRequestQueue中根据api版本不同,创建的HurlStack或HttpClientStack,前面已经说过两者之间的差别,我们选版本高的来讲,这里值得一提的是,之所以在api9之后不用HttpClient,是因为它有所缺陷,好了,进入正题:

public HurlStack() {
this(null);
}


继续看:

public HurlStack(UrlRewriter urlRewriter) {
this(urlRewriter, null);
}


再看:

public HurlStack(UrlRewriter urlRewriter, SSLSocketFactory sslSocketFactory) {
mUrlRewriter = urlRewriter;
mSslSocketFactory = sslSocketFactory;
}


UrlRewriter是HurlStack中的一个内部接口,用于URL的重置,我们给的是null,所以不用管它,SSLSocketFactory是https协议用到的类,我们给的也是null,所以也不需要管它,直入主题看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);
HttpURLConnection connection = openConnection(parsedUrl, request);
// 添加请求头
for (String headerName : map.keySet()) {
connection.addRequestProperty(headerName, map.get(headerName));
}
setConnectionParametersForRequest(connection, request);
// Initialize HttpResponse with data from the HttpURLConnection.
ProtocolVersion protocolVersion = new ProtocolVersion("HTTP", 1, 1);
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.");
}
StatusLine responseStatus = new BasicStatusLine(protocolVersion,
connection.getResponseCode(), connection.getResponseMessage());
BasicHttpResponse response = new BasicHttpResponse(responseStatus);
response.setEntity(entityFromConnection(connection));
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;
}


前面都很简单,我们直接看第16行的openConnection方法:

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
// 如果是https协议
if ("https".equals(url.getProtocol()) && mSslSocketFactory != null) {
((HttpsURLConnection)connection).setSSLSocketFactory(mSslSocketFactory);
}

return connection;
}


再看createConnection方法:

protected HttpURLConnection createConnection(URL url) throws IOException {
return (HttpURLConnection) url.openConnection();
}


很简单吧,仅仅只是封装了(HttpURLConnection) url.openConnection()这一句代码而已,那么上面也就简单了,只是对网络请求进行了一些简单的设置,判断是否是https协议,进行设置。

这里提一点request.getTimeoutMs()获取到的时间其实是DefaultRetryPolicy中mCurrentTimeoutMs,当请求重试时,连接超时的时间会被延长。

随后就是添加请求头,setConnectionParametersForRequest方法用于确定请求方式:

static void setConnectionParametersForRequest(HttpURLConnection connection,
Request<?> request) throws IOException, AuthFailureError {
switch (request.getMethod()) {
case Method.DEPRECATED_GET_OR_POST:
// This is the deprecated way that needs to be handled for backwards compatibility.
// If the request's post body is null, then the assumption is that the request is
// GET.  Otherwise, it is assumed that the request is a POST.
byte[] postBody = request.getPostBody();
if (postBody != null) {
// Prepare output. There is no need to set Content-Length explicitly,
// since this is handled by HttpURLConnection using the size of the prepared
// output stream.
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.addRequestProperty(HEADER_CONTENT_TYPE,
request.getPostBodyContentType());
DataOutputStream out = new DataOutputStream(connection.getOutputStream());
out.write(postBody);
out.close();
}
break;
case Method.GET:
// Not necessary to set the request method because connection defaults to GET but
// being explicit here.
connection.setRequestMethod("GET");
break;
case Method.DELETE:
connection.setRequestMethod("DELETE");
break;
case Method.POST:
connection.setRequestMethod("POST");
addBodyIfExists(connection, request);
break;
case Method.PUT:
connection.setRequestMethod("PUT");
addBodyIfExists(connection, request);
break;
default:
throw new IllegalStateException("Unknown method type.");
}
}


包含GET,DELETE,POST,PUT等等,第一种请无视它,大概的意思是这是过时的,需要处理的向后兼容性,如果该请求的正文无效,则该假设是该请求是GET,否则是POST,老实说我也不知道它想表达什么意思,如果有大神知道还望指教!

之后就是为了统一返回方式,将HttpURLConnection中的属性给予了封装,先是http协议版本,然后封装成状态行,再然后放入BasicHttpResponse中,设置实体,entityFromConnection方法,猜也猜的到是做什么用的:

/**
* Initializes an {@link HttpEntity} from the given {@link HttpURLConnection}.
* @param connection
* @return an HttpEntity populated with data from <code>connection</code>.
*
* 将HttpURLConnection换成HttpEntity
*/
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;
}


很简单,我就不废话了。

最后添加响应头,一个HttpResponse就封装完成了。

到此Volley网络请求这一条线,我们已经全部走完了,希望各位读者能有所收获!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息