Volley源码解析<六> HttpStack网络请求
@[Volley, 网络请求, HttpStack]
声明:转载请注明出处,知识有限,如有错误,请多多交流指正!
HttpStack网络请求结构
HttpStack接口说明
HttpStack处理 Http 请求,返回请求结果,只有一个抽象方法,子类实现
public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)throws IOException, AuthFailureError;
request
:请求数据additionalHeaders
:添加额外的请求 HeadersHttpResponse
:返回结果
HurlStack请求
主要内部主要封装实现HttpURLConnection
1. 构造方法
public HurlStack()
public HurlStack(UrlRewriter urlRewriter)
public HurlStack(UrlRewriter urlRewriter, SSLSocketFactory sslSocketFactory)
其中
urlRewriter
:对url进行重写,重写的好处使url更加的保密,安全
sslSocketFactory
:用于Https请求
Volley.java
调用public HurlStack()
,也就urlRewriter和sslSocketFactory都设置为Null,也就是不设置
2. 主要调用performRequest
方法发起请求
代码流程
- 添加head:请求head+额外的head
- 设置是否对url进行重写
- 通过openConnection
建立连接
- 设置请求的相关属性
- 获取响应码和响应信息处理
- 处理数据和head,返回数据
@Override
public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
throws IOException, AuthFailureError {
String url = request.getUrl();
//添加head:请求head+额外的head
HashMap<String, String> map = new HashMap<String, String>();
map.putAll(request.getHeaders());
map.putAll(additionalHeaders);
//目前没有使用到,对url进行重写,重写的好处使url更加的保密,安全
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);
//获取响应中的实体
if (hasResponseBody(request.getMethod(), responseStatus.getStatusCode())) {
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;
}
private HttpURLConnection openConnection(URL url, Request
// use caller-provided custom SslSocketFactory, if any, for HTTPS
if ("https".equals(url.getProtocol()) && mSslSocketFactory != null) {
//设置自定义SSL Https连接
((HttpsURLConnection) connection).setSSLSocketFactory(mSslSocketFactory);
}
默认请求连接和读取的时间是2.5s,通过代码追踪在DefaultRetryPolicy
中
public static final int DEFAULT_TIMEOUT_MS = 2500;
static void setConnectionParametersForRequest(HttpURLConnection connection,Request
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:
...省略...
}
}
Method.DEPRECATED_GET_OR_POST这个请求是什么?
按照注释所说:这是一个过时的的方法为了向后兼容。如果请求的body为空,那么请求就是GET请求;否则这个请求就是POST请求,那么假如postBody为空,没有处理,这是不是一个bug?
不是bug,因为HttpURLConnection 的默认值是GET,可以不用设置,所以没有else;
Method.DEPRECATED_GET_OR_POST:如果有人知道这是什么请求,麻烦请告之!!!
为什么connection.getResponseCode(401)就会抛出IOException?(volley 401错误处理)
volley 401 错误产生原因和解决方案 :
http://blog.csdn.net/kufeiyun/article/details/44646145
http://stackoverflow.com/questions/30476584/android-volley-strange-error-with-http-code-401-java-io-ioexception-no-authe
结果数据封装
private static HttpEntity entityFromConnection(HttpURLConnection connection)
将获取到的数据封装到HttpEntity中,在封装到BasicHttpResponse,返回数据
网络请求携带请求数据
private static void addBodyIfExists(HttpURLConnection connection, Request
HttpClientStack请求
主要内部主要封装实现HttpClient
1. 构造方法
public HttpClientStack(HttpClient client)
其中
client
:Volley.java调用了 stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));传入的是AndroidHttpClient
AndroidHttpClient是什么?
可以阅读HTTP服务(7):AndroidHttpClient博客
2. 网络请求调用newRequestQueue
方法
public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders) throws IOException, AuthFailureError {
//创建请求
HttpUriRequest httpRequest = createHttpRequest(request, additionalHeaders);
//添加head
addHeaders(httpRequest, additionalHeaders);
addHeaders(httpRequest, request.getHeaders());
//准备请求回调
onPrepareRequest(httpRequest);
HttpParams httpParams = httpRequest.getParams();
int timeoutMs = request.getTimeoutMs();
// TODO: Reevaluate this connection timeout based on more wide-scale
// data collection and possibly different for wifi vs. 3G.
// 设置连接超时时间5S
HttpConnectionParams.setConnectionTimeout(httpParams, 5000);
// 设置请求超时,默认设置2.5s
HttpConnectionParams.setSoTimeout(httpParams, timeoutMs);
// 执行
return mClient.execute(httpRequest);
}
与HurlStack
不同的是,HttpClientStack
设置连接超时时间是5S,而HurlStack是2.5s
3. 其他方法
private static void addHeaders(HttpUriRequest httpRequest, Map<String, String> headers):设置head
private static List<NameValuePair> getPostParameterPairs(Map<String, String> postParams):将Map数据转成List<NameValuePair>
static HttpUriRequest createHttpRequest(Request<?> request, Map<String, String> additionalHeaders):创建请求方式
private static void setEntityIfNonEmptyBody(HttpEntityEnclosingRequestBase httpRequest, Request<?> request):设置body数据