Volley框架解析(五)-----HttpStack接口及其默认实现类解析
来源:互联网 发布:linux nc 发送数据 编辑:程序博客网 时间:2024/06/16 01:37
Volley框架解析(五)—–HttpStack接口及其默认实现类解析
1. 前言(可直接无视跳过= =
历经前面的四篇,终于涉及到网络请求核心的内容了,前面都在做一些准备工作,以及对request队列调度以及维护工作。之前一直说,httpResponse = mHttpStack.performRequest(request, headers);
这句话是网络请求的核心,因为这句话一出来,神不知鬼不觉的request就被发出去了,并且还带回来一个HttpResponse的实例= =,有没有感觉被忽悠了,今天就深入进去一探究竟0.0。
2. HttpStack.java
接口类,里面包含了一个方法,performRequest()
。
/** * An HTTP stack abstraction. */public interface HttpStack { /** * Performs an HTTP request with the given parameters. * 用传入给定的参数来模拟Http请求 * * 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(). * 如果传入的request.getPostBody()为空,则发送一个Get类型的请求,否则发送一个Post类型请求 * * @param request the request to perform * 即将发送的初始请求,也是volley自己写的= =,进去看看 * (还需要添加上额外的header * * @param additionalHeaders additional headers to be sent together with * {@link Request#getHeaders()} * 需要添加到该request上的header的信息 * * @return the HTTP response * */ public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders) throws IOException, AuthFailureError;}
3. HttpClientStack.java
当sdk版本小于2.3时,Volley会选择用HttpClient来实现请求的发送。
/** * An HttpStack that performs request over an {@link HttpClient}. * 在sdk小于2.3的时候 * 选用HttpClient来实现网络请求 */public class HttpClientStack implements HttpStack { /** * 官方文档 * Interface for an HTTP client. * HTTP clients encapsulate a smorgasbord of objects required to execute HTTP requests while handling cookies, * authentication, connection management, and other features. * HTTP Clients将发送http请求需要需要做出的信息 * Thread safety of HTTP clients depends on the implementation and configuration of the specific client. * */ protected final HttpClient mClient; //Http请求头里面的固定格式 private final static String HEADER_CONTENT_TYPE = "Content-Type"; public HttpClientStack(HttpClient client) { mClient = client; } //在组合出一个请求的过程中,向请求体中添加Header的方法,Header是以键值对的形式存在的 private static void addHeaders(HttpUriRequest httpRequest, Map<String, String> headers) { for (String key : headers.keySet()) { httpRequest.setHeader(key, headers.get(key)); } } /** * NameValuePair 官方文档 * A simple class encapsulating an attribute/value pair. * * 该函数将传入的Map里面存放的值进一步转化成由NameValuePair子类组成的数组中 */ @SuppressWarnings("unused") private static List<NameValuePair> getPostParameterPairs(Map<String, String> postParams) { List<NameValuePair> result = new ArrayList<NameValuePair>(postParams.size()); for (String key : postParams.keySet()) { result.add(new BasicNameValuePair(key, postParams.get(key))); } return result; } //该函数也就是实现HttpStack接口需要实现的方法,用来执行Request的方法 @Override public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders) throws IOException, AuthFailureError { /** * 传入请求体和额外需要添加入的头部 * 生成并返回一个HttpUriRequest */ HttpUriRequest httpRequest = createHttpRequest(request, additionalHeaders); /** * 这个方法在前面实现了,将这些传入的键值对全部添加到httpRequest里面去 */ addHeaders(httpRequest, additionalHeaders); addHeaders(httpRequest, request.getHeaders()); /** * 一个protected方法,留给子类可以实现的方法(本类中并没有什么东西),在这里会调用。 */ onPrepareRequest(httpRequest); /** * HttpParams 官方文档 * Represents a collection of HTTP protocol and framework parameters. * 说白了就是Http协议和框架的相关参数 */ HttpParams httpParams = httpRequest.getParams(); int timeoutMs = request.getTimeoutMs(); /** * HttpConnectionParams 官方文档 * An adaptor for accessing connection parameters in HttpParams. * 一个用来访问请求参数的适配器 * Note that the implements relation to CoreConnectionPNames is for compatibility with existing application code only. * References to the parameter names should use the interface, not this class. */ /* Sets the timeout until a connection is established. * 该方法用来设置时间限制, * A value of zero means the timeout is not used. The default value is zero. * 如果timeout设置为0则表示该限时没有启用,默认为0 */ HttpConnectionParams.setConnectionTimeout(httpParams, 5000); /** * Sets the default socket timeout (SO_TIMEOUT) in milliseconds which is the timeout for waiting for data. * 设置请求发出后等待网络响应并返回数据的限时 * A timeout value of zero is interpreted as an infinite timeout. * 如果timeout值为0则意味着无限等待,没有等待限时,同时也是默认的值 * This value is used when no socket timeout is set in the method parameters. */ HttpConnectionParams.setSoTimeout(httpParams, timeoutMs); /** * 执行了HttpClient类中的execute方法 * 方法描述为 Executes a request using the default context. * 方法结束后将返回一个HttpResponse,也就是请求的结果类 */ return mClient.execute(httpRequest); } /** * Creates the appropriate subclass of HttpUriRequest for passed in request. * 根据传入的Request种类不同 * 创建不同的HttpUriRequest子类(也就是下面的HttpGet等等) * 下面做的工作和HurlStack.java里面做的工作差不多 * 设置header,以及是否需要传入请求携带的参数 * 只是本类中用HttpClient实现,后者用的是HttpURLConnection实现的 */ @SuppressWarnings("deprecation") /* protected */ static HttpUriRequest createHttpRequest(Request<?> request, Map<String, String> additionalHeaders) throws 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) { HttpPost postRequest = new HttpPost(request.getUrl()); postRequest.addHeader(HEADER_CONTENT_TYPE, request.getPostBodyContentType()); HttpEntity entity; entity = new ByteArrayEntity(postBody); postRequest.setEntity(entity); return postRequest; } else { return new HttpGet(request.getUrl()); } } case Method.GET: return new HttpGet(request.getUrl()); case Method.DELETE: return new HttpDelete(request.getUrl()); case Method.POST: { HttpPost postRequest = new HttpPost(request.getUrl()); postRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType()); setEntityIfNonEmptyBody(postRequest, request); return postRequest; } case Method.PUT: { HttpPut putRequest = new HttpPut(request.getUrl()); putRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType()); setEntityIfNonEmptyBody(putRequest, request); return putRequest; } case Method.HEAD: return new HttpHead(request.getUrl()); case Method.OPTIONS: return new HttpOptions(request.getUrl()); case Method.TRACE: return new HttpTrace(request.getUrl()); case Method.PATCH: { HttpPatch patchRequest = new HttpPatch(request.getUrl()); patchRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType()); setEntityIfNonEmptyBody(patchRequest, request); return patchRequest; } default: throw new IllegalStateException("Unknown request method."); } } private static void setEntityIfNonEmptyBody(HttpEntityEnclosingRequestBase httpRequest, Request<?> request) throws AuthFailureError { byte[] body = request.getBody(); if (body != null) { HttpEntity entity = new ByteArrayEntity(body); httpRequest.setEntity(entity); } } /** * Called before the request is executed using the underlying HttpClient. * * <p>Overwrite in subclasses to augment the request.</p> */ protected void onPrepareRequest(HttpUriRequest request) throws IOException { // Nothing. } /** * The HttpPatch class does not exist in the Android framework, so this has been defined here. * = =在HttpUriClient的子类中没有支持Patch的请求方法 * 在这里volley实现了= = */ public static final class HttpPatch extends HttpEntityEnclosingRequestBase { public final static String METHOD_NAME = "PATCH"; public HttpPatch() { super(); } public HttpPatch(final URI uri) { super(); setURI(uri); } /** * @throws IllegalArgumentException if the uri is invalid. */ public HttpPatch(final String uri) { super(); setURI(URI.create(uri)); } @Override public String getMethod() { return METHOD_NAME; } }}
4.HurlStack.java
在sdk大于2.3的android手机上,Volley选择用HttpURLConnection来实现网络请求。
/** * An {@link HttpStack} based on {@link HttpURLConnection}. *//** * 当os version 版本在2.3以上,也就是sdk >= 9 的时候 * 选用这个接口作为HttpStack, 用到了HttpURLConnection * 关于HttpURLConnection,官方解释为: * An URLConnection for HTTP (RFC 2616) used to send and receive data over the web. * Data may be of any type and length. * This class may be used to send and receive streaming data whose length is not known in advance. * 用来发送和接受数据,数据可以为任意的形式及长度 * 这个类常用来发送和接受数据流里面长度不定的数据. */public class HurlStack implements HttpStack { /* * 请求header中的一个关键字 * content-type代表着被发送的请求中主体内容 * 可以设置application/json等格式 */ private static final String HEADER_CONTENT_TYPE = "Content-Type"; /** * An interface for transforming URLs before use. * 一个用来在使用url之前,将url处理的接口工具 * 可能是用来规范url格式的一个工具= = */ public interface UrlRewriter { /** * Returns a URL to use instead of the provided one, or null to indicate * this URL should not be used at all. */ public String rewriteUrl(String originalUrl); } private final UrlRewriter mUrlRewriter; /** * The abstract factory implementation to create SSLSockets. * 是一个抽象工厂类,用来创建SSLSockets(还是不懂是个什么鬼 * * 对于SSLSocket,官方的解释是这样的: * The extension of Socket providing secure protocols like SSL (Secure Sockets Layer) or TLS (Transport Layer Security). * 是Socket的子类,并在之基础上新增了类似于SSL或者TLS等等的安全协议. */ private final SSLSocketFactory mSslSocketFactory; 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; } /** * 该函数为HttpStack的接口 */ @Override public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders) throws IOException, AuthFailureError { /** * 得到请求的url */ String url = request.getUrl(); /** * 创建一个新的HashMap * 用来存放请求的header的信息 */ HashMap<String, String> map = new HashMap<String, String>(); /** * 将原request(volley自己封装的一个request类)中的header * 和另外需要添加入header的信息都整合起来 */ 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字符串形式规范成一个URL的类对象 */ URL parsedUrl = new URL(url); /** * HurlStack类是在sdk>=2.3的android版本上使用的 * 这里面用到了HttpURLConnection类 * 在函数里面打开了并返回了一个HttpURLConnection * 设置了HttpURLConnection的响应超时阀值 */ HttpURLConnection connection = openConnection(parsedUrl, request); /** * 开始给HttpURLConnection添加header的信息 * 用addRequestProperty()函数将header以键值对的形式填入 */ for (String headerName : map.keySet()) { connection.addRequestProperty(headerName, map.get(headerName)); } /** * 根据request种类的不同 * 分别用不同的方式来处理其中的参数 */ 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; } /** * Initializes an {@link HttpEntity} from the given {@link HttpURLConnection}. * @param connection * @return an HttpEntity populated with data from <code>connection</code>. */ 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; } /** * Create an {@link HttpURLConnection} for the specified {@code url}. */ protected HttpURLConnection createConnection(URL url) throws IOException { return (HttpURLConnection) url.openConnection(); } /** * Opens an {@link HttpURLConnection} with parameters. * 通过给的url和参数,打开一个HttpURLConnection * @param url * @return an open connection * @throws IOException */ private HttpURLConnection openConnection(URL url, Request<?> request) throws IOException { HttpURLConnection connection = createConnection(url); /** * 通过Request.java中的函数 * 获取到该request上所设置的服务器最大响应时间阀值 * 该阀值默认是2500ms,而且可能会随着retry的次数而增大 */ int timeoutMs = request.getTimeoutMs(); /** * 给connection设置上请求超时时间 */ 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; } @SuppressWarnings("deprecation") /* package */ /** * switch不同的请求方法 * 来以不同的方式给HttpURLConnection添加请求参数 */ static void setConnectionParametersForRequest(HttpURLConnection connection, Request<?> request) throws IOException, AuthFailureError { switch (request.getMethod()) { /** * 在构造Request的时候如果没有指明请求方式 * DEPRECATED_GET_OR_POST为其默认值 * 通过postBody是否为Null来区别POST和GET * 这两种最常用的请求方式 */ 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. /** * 不要用这个参数了= =,因为不能处理什么DELETE之类的 * 该方法已经过时了。 */ 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设置请求的方式 */ connection.setRequestMethod("POST"); /** * 设置http请求头中的content-type参数 */ connection.addRequestProperty(HEADER_CONTENT_TYPE, request.getPostBodyContentType()); DataOutputStream out = new DataOutputStream(connection.getOutputStream()); out.write(0); 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; 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."); } } /** * 如果存在请求参数的话 * 获取到connection的输出流对象 * 并创建一个DataOutputStream对象 * 用于向服务器写入需要传递的参数 */ 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(); } }}
如果上面的注释有什么错误的地方,还望大家给与指正= =。
0 0
- Volley框架解析(五)-----HttpStack接口及其默认实现类解析
- Volley框架解析(四)-----Network接口及其默认实现类解析
- Volley框架解析(六)-----Cache接口及其默认实现类解析
- 谷歌Volley网络框架讲解——HttpStack及其实现类
- 谷歌Volley网络框架讲解——HttpStack及其实现类
- 谷歌Volley网络框架讲解——HttpStack及其实现类
- Volley源码解析<六> HttpStack网络请求
- android网络框架volley学习之HttpStack接口
- Volley框架全解析
- 源码解析Volley框架
- android 框架 volley 解析
- Volley框架解析
- Volley框架解析
- Android Volley框架解析
- Android Volley框架解析
- volley解析请求框架
- Volley框架源码解析
- volley 网络框架解析
- C++各大有名库的介绍 http://my.oschina.net/qihh/blog/55591
- Hadoop集群MapReduce经典案例
- Xcode快速入门-1-PlayGround
- CentOS7安装nagios并配置出图详解
- 关于Edittext边框的
- Volley框架解析(五)-----HttpStack接口及其默认实现类解析
- linux下网站文件的自动备份
- LeetCode-Summary Ranges
- 天声人語 20150917
- 解析xml数据
- IOS学的容易----ARC与MRC 的切换
- SIFT GPU 优化思路整理
- 线性表的单链表
- HDU 5441 并查集