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

android网络框架volley学习之HttpStack接口

2015-04-01 16:40 453 查看
这篇博文将介绍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类,这里就不说明了。

不对之处,请大家指正,谢谢!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: