HttpStack是一个接口,只有一个方法。主要用于请求网络数据,并返回结果。
1 2 3 4 public interface HttpStack { public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders) throws IOException, AuthFailureError; }
HttpStack有两个实现类,HurlStack和HttpClientStack,HurlStack是利用HttpUrlConnection实现的,HttpClientStack是利用HttpClient实现的。
在Volley的newRequestQueue(Context context, HttpStack stack)方法中,如果用户传入的HttpStack为空的话,会自动的根据当前系统的版本来创建HttpStack的实现类,如果SDK大于等于9,也就是Android 2.3以后,会创建HurlStack,否则会创建HttpClientStack。
关于HurlStack和HttpClientStack的优劣的问题,建议阅读:Android访问网络,使用HttpURLConnection还是HttpClient?
1 2 3 在Android 2.2版本之前,HttpClient拥有较少的bug,因此使用它是最好的选择。 而在Android 2.3版本及以后,HttpURLConnection则是最佳的选择。它的API简单,体积较小,因而非常适用于Android项目。压缩和缓存机制可以有效地减少网络访问的流量,在提升速度和省电方面也起到了较大的作用。对于新的应用程序应该更加偏向于使用HttpURLConnection,因为在以后的工作当中我们也会将更多的时间放在优化HttpURLConnection上面。
若用户想要使用其他的网络请求类库,比如okhttp等就可以实现HttpStack接口,并在performRequest方法中调用okhttp进行网络请求,并把请求的结果封装成一个HttpResponse返回即可,HttpResponse中包含了状态码,响应头,body信息。
HttpStack的两个子类HurlStack &HttpClientStack 。由于HurlStack和HttpClientStack的实现机制是一样的,只是使用的类不一样,我们这篇文章就只讲解HurlStack了。
HurlStack提供了三个构造函数,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public HurlStack() { this(null); } /** * @param urlRewriter Rewriter to use for request URLs */ public HurlStack(UrlRewriter urlRewriter) { this(urlRewriter, null); } /** * @param urlRewriter Rewriter to use for request URLs * @param sslSocketFactory SSL factory to use for HTTPS connections */ public HurlStack(UrlRewriter urlRewriter, SSLSocketFactory sslSocketFactory) { mUrlRewriter = urlRewriter; mSslSocketFactory = sslSocketFactory; }
其中第一个就是Volley类中使用的构造函数,但其实最终调用的都是
1 2 3 4 public HurlStack(UrlRewriter urlRewriter, SSLSocketFactory sslSocketFactory) { mUrlRewriter = urlRewriter; mSslSocketFactory = sslSocketFactory; }
默认这两个类都是为null的,但是如果我们要实现对Url的拦截,对url进行一些处理的话,或者利用Https来保证数据传输的安全性的话,我们就可以传入自己实现的UrlRewriterc对象,或者添加SSlSocketFactory。不过在我们一般的项目中,一般用不到,只要稍微了解一下就好。 接下来,看最主要的performRequest方法:
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 28 29 30 31 32 33 34 35 36 37 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());//默认为null map.putAll(additionalHeaders);//添加头部,主要是缓存相关的头部信息 if (mUrlRewriter != null) { ...//代码不执行 } URL parsedUrl = new URL(url); HttpURLConnection connection = openConnection(parsedUrl, request);//打开Connection for (String headerName : map.keySet()) { //将Map的对象添加到Connection的属性中 connection.addRequestProperty(headerName, map.get(headerName)); } //设置connection方法,主要是设置Method属性和Content(for post/put) setConnectionParametersForRequest(connection, request); // Initialize HttpResponse with data from the HttpURLConnection. ProtocolVersion protocolVersion = new ProtocolVersion("HTTP", 1, 1);//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的Entity对象 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; }
HttpURLConnection是Android3.0以后才提供的一个网络访问类,而HurlStack类,也正是H(ttp)URL的缩写,所以这个类,其实就是基于HttpUrlConnection的实现,其步骤如下: 1)从Request中获得url参数,根据url参数构造URL对象,而URL对象是java提供的获取网络资源的一个封装好的实用类。 2)从URL对象打开Connection,并设置connection的超时,缓存,让网络资源写入等属性。
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 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; } protected HttpURLConnection createConnection(URL url) throws IOException { HttpURLConnection connection = (HttpURLConnection) url.openConnection(); //设置所有的http连接是否自动处理重定向; // public static void HttpURLConnection.setFollowRedirects(boolean //followRedirects) //设置本次连接是否自动处理重定向。设置成true,系统自动处理重定向;设置成false则需要自己从http reply中分析新的url自己重新连接。 connection.setInstanceFollowRedirects(HttpURLConnection.getFollowRedirects()); return connection; }
3)调用方法 setConnectionParametersForRequest来设置Method属性,如果是Post或者Put的话,还要设置Content内容。
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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 static void setConnectionParametersForRequest(HttpURLConnection connection, Request<?> request) throws IOException, AuthFailureError { switch (request.getMethod()) { case Method.DEPRECATED_GET_OR_POST: byte[] postBody = request.getPostBody(); if (postBody != null) { 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: 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; case Method.HEAD: connection.setRequestMethod("HEAD"); break; case Method.OPTIONS: connection.setRequestMethod("OPTIONS"); break; case Method.TRACE: connection.setRequestMethod("TRACE"); break; case Method.PATCH: connection.setRequestMethod("PATCH"); addBodyIfExists(connection, request); break; default: throw new IllegalStateException("Unknown method type."); } } private static void addBodyIfExists(HttpURLConnection connection, Request<?> request) throws IOException, AuthFailureError { byte[] body = request.getBody(); if (body != null) { connection.setDoOutput(true); connection.addRequestProperty(HEADER_CONTENT_TYPE, request.getBodyContentType()); DataOutputStream out = new DataOutputStream(connection.getOutputStream()); out.write(body); out.close(); } }
4)设置Http 协议,这里基本上是1.1了。
1 ProtocolVersion protocolVersion = new ProtocolVersion("HTTP", 1, 1);
5)获得Response的流,并将其解析成对应的HttpEntity对象,设置给Response.entity字段,返回给BasicNetwork。
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 28 29 30 31 32 33 34 35 36 37 38 int responseCode = connection.getResponseCode(); if (responseCode == -1) { 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); } } private static boolean hasResponseBody(int requestMethod, int responseCode) { return requestMethod != Request.Method.HEAD && !(HttpStatus.SC_CONTINUE <= responseCode && responseCode < HttpStatus.SC_OK) && responseCode != HttpStatus.SC_NO_CONTENT && responseCode != HttpStatus.SC_NOT_MODIFIED; } 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; }
6)BasicNetwork获得返回来的Response对象,就会由Request去解析这个Response对象,因为不同的请求返回来的对象是不一样的,所以这个解析的过程必须由各个请求的实现类自己去实现,也即如ImageRequest,JsonObjectRequest对象等,都要实现自己的parseNetworkResponse方法。
相关HTTP知识:
Http status code : 304 HTTP状态码
HttpUrlConnection相关知识:
关于HttpURLConnection.setFollowRedirects 如何通过HttpURLConnection得到http 302的跳转地址
HttpUrlConnection的setDoOutput与setDoInput的区别 HttpURLConnection用法详解
Android中TrafficStats流量监控类
Android访问网络,使用HttpURLConnection还是HttpClient?
参考链接:
Android中关于Volley的使用(九)认识HurlStack(HttpClientStack) volley源码解析(六)–HurlStack与HttpClientStack之争 Android中的volley_3_网络请求HttpStack、HttpClientStack和HurlStack
上一篇:Volley-PoolingByteArrayOutputStream源码解析
下一篇:Volley-ByteArrayPool源码分析