这篇博文将介绍Volley框架的实际网络访问类HurlStack和HttpClientStack.这两个类均实现了HttpStack接口,只是采用了不同的网络访问类。HurlStack类是利用通过URL打开httpURLconnection网络通信连接,实现了网络访问。而HttpClientStack则是利用android中org.apache.http系列的开发包实现网络访问,实现过程较为简单。这两个类都是是Volley进行网络访问的实际类。
下面逐个查看这两个类的代码
HurlStack类
//利用httpURLconnection建立一个httpStack public class HurlStack implements HttpStack { private static final String HEADER_CONTENT_TYPE = "Content-Type"; //接口用于重新书写URL public interface UrlRewriter { public String rewriteUrl(String originalUrl); } private final UrlRewriter mUrlRewriter; public HurlStack() { this(null); } public HurlStack(UrlRewriter urlRewriter) { this(urlRewriter, null); } public HurlStack(UrlRewriter urlRewriter, SSLSocketFactory sslSocketFactory) { mUrlRewriter = urlRewriter; mSslSocketFactory = sslSocketFactory; } //实现未实现的方法 @Override public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders) throws IOException, AuthFailureError { //获取请求体中的URL String url = request.getUrl(); //建立一个map用于存放请求头信息 HashMap<String, String> map = new HashMap<String, String>(); //将原来请求体中的请求头添加到map中 map.putAll(request.getHeaders()); //添加额外的请求头 map.putAll(additionalHeaders); //如果mUrlRewriter不为空则重写URL if (mUrlRewriter != null) { String rewritten = mUrlRewriter.rewriteUrl(url); if (rewritten == null) { throw new IOException("URL blocked by rewriter: " + url); } url = rewritten; } //通过String建立URL对象 URL parsedUrl = new URL(url); //打开http通信链接 HttpURLConnection connection = openConnection(parsedUrl, request); //为通信连接添加请求头 for (String headerName : map.keySet()) { connection.addRequestProperty(headerName, map.get(headerName)); } //设置通信链接的参数 setConnectionParametersForRequest(connection, request); /* 用请求回来的响应来构造HTTPResponse对象 *1、建立协议控制版本的对象。 *2、利用协议版本对象构建响应行对象。 *3、构建HTTPResponse对象。 **/ 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); //为HTTPResponse添加实体 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 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; } //建立http通信链接 protected HttpURLConnection createConnection(URL url) throws IOException { return (HttpURLConnection) url.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 if ("https".equals(url.getProtocol()) && mSslSocketFactory != null) { ((HttpsURLConnection)connection).setSSLSocketFactory(mSslSocketFactory); } return connection; } //根据请求体的方法 对通信链接的参数进行设置 static void setConnectionParametersForRequest(HttpURLConnection connection, Request<?> request) throws IOException, AuthFailureError { switch (request.getMethod()) { case Method.GET: //这里其实不需要设置get方法,因为connection默认的就是get方法 connection.setRequestMethod("GET"); break; case Method.POST: connection.setRequestMethod("POST"); addBodyIfExists(connection, request); break; } } //如果是post方法则添加请求体 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(); } } }
整个网络访问和生成httpResponse对象的步骤基本可以概括为:
1、通过URL建立网络通信连接得到httpURLconnection对象。
2、对httpURLconnection对象进行一系列的设置,包括方法、请求头、以及访问链接超时等,如果是post请求则需要设置httpURLconnection的输出为true,接着用流的形式写入到请求体中。
3、建立协议控制版本的对象,同时利用协议版本对象构建响应行对象最终生成HTTPResponse对象。
4、为生成的HTTPResponse对象(通过httpURLconnection对象)添加实体和响应头。
HttpClientStack类
public class HttpClientStack implements HttpStack { //请求的客户端 protected final HttpClient mClient; //内容类型的头 private final static String HEADER_CONTENT_TYPE = "Content-Type"; //构造函数 public HttpClientStack(HttpClient client) { mClient = client; } //添加头信息 private static void addHeaders(HttpUriRequest httpRequest, Map<String, String> headers) { for (String key : headers.keySet()) { httpRequest.setHeader(key, headers.get(key)); } } //将map形式的请求参数转化成NameValuePair对象存储在list集合中 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; } @Override public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders) throws IOException, AuthFailureError { //创建请求报文 HttpUriRequest httpRequest = createHttpRequest(request, additionalHeaders); addHeaders(httpRequest, additionalHeaders);//添加额外的请求头信息 addHeaders(httpRequest, request.getHeaders());//添加从request中获取的请求头 HttpParams httpParams = httpRequest.getParams();//获取请求的参数的引用 int timeoutMs = request.getTimeoutMs(); //通过HttpConnectionParams的静态方法对httpParams的一些参数进行设置 HttpConnectionParams.setConnectionTimeout(httpParams, 5000); HttpConnectionParams.setSoTimeout(httpParams, timeoutMs); return mClient.execute(httpRequest);//执行请求同时返回HTTPResponse对象 } //根据request对象的方法建立不同的请求报文 static HttpUriRequest createHttpRequest(Request<?> request, Map<String, String> additionalHeaders) throws AuthFailureError { switch (request.getMethod()) { //创建get请求httpGet case Method.GET: return new HttpGet(request.getUrl()); //创建post请求httpPost case Method.POST: { HttpPost postRequest = new HttpPost(request.getUrl()); postRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType()); setEntityIfNonEmptyBody(postRequest, request); return postRequest; } } } //为post请求添加实体 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); } } }
HttpClientStack生成httpResponse的过程如下:
1、建立httpclient,android中实现的类有DefaultHttpClient和AndroidHttpClient。
2、根据request的方法创建不同的请求报文(post请求需要添加实体)。
3、为请求添加请求头同时设置一些参数信息。
4、调用httpclient的execute方法执行请求,生成httpResponse对象并返回。
以上就基于httpStack接口的两个最真实的网络访问类的实现过程。前面也是多次提到在什么情况使用HurlStack类喝HttpClientStack类,这里就不说明了。
不对之处,请大家指正,谢谢!