HttpStack及其实现类

前两篇已经对网络请求流程已经梳理了个大概,这次我们着重看一下HttpStack和它的其实现类。我们之前在Network篇讲过它仅有一个实现类,而今天我们讲的HttpStack有两个实现类。

其中HttpCliantStack是在2.3以下使用,Hurl是在2.3以上使用,这样分开的原因谷歌给了注释。

  // Prior to Gingerbread, HttpUrlConnection was unreliable.
// See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html

2.3以下HttpUrlConnection 是不能用的,而2.3以上就是采用HttpUrlConnection 进行连接的,以下就是直接用的HttpClient。

HttpStack

先来看一下HttpStack接口

public interface HttpStack {
/**
* Performs an HTTP request with the given parameters.
*通过给定的参数执行一个http请求
* <p>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().</p>
*
* @param request the request to perform//要执行的请求
* @param additionalHeaders additional headers to be sent together with
* {@link Request#getHeaders()}
* @return the HTTP response//执行一个请求返回一个结果
*/
public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
throws IOException, AuthFailureError; }

HttpCliantStack

这里区分Get和Post请求,我们先看下HttpCliantStack,注释已经写的非常清楚了,如果注释有误望大家指出。

/**
* An HttpStack that performs request over an {@link HttpClient}.
* HttpStack:通过HttpClient执行请求
* {@link Volley#newRequestQueue(android.content.Context, HttpStack)}
*/
public class HttpClientStack implements HttpStack { protected final HttpClient mClient;//默认HttpClient /** The Constant HEADER_CONTENT_TYPE. */
private final static String HEADER_CONTENT_TYPE = "Content-Type"; /**
* Instantiates a new http client stack.
* Volley中HttpClient可是AndroidHttpClient.newInstance(userAgent)产生的
* @param client the client
*/
public HttpClientStack(HttpClient client) {
mClient = client;
} /**
* Adds the headers.
*
* @param httpRequest the http request
* @param headers the headers
*/
private static void addHeaders(HttpUriRequest httpRequest, Map<String, String> headers) {
for (String key : headers.keySet()) {
httpRequest.setHeader(key, headers.get(key));
}
} /**
* Gets the post parameter pairs.
*
* @param postParams the post params
* @return the post parameter pairs
*/
@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;
} /* (non-Javadoc)
* @see com.android.volley.toolbox.HttpStack#performRequest(com.android.volley.Request, java.util.Map)
*/ @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());//添加请求自带头部
onPrepareRequest(httpRequest);//相当于onStart,子类扩展
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.
/** 如果有更大规模的数据在Wifi和3G网络下重新评估连接超时*/
HttpConnectionParams.setConnectionTimeout(httpParams, 5000);//设置超时
HttpConnectionParams.setSoTimeout(httpParams, timeoutMs);//设置超时
return mClient.execute(httpRequest);
} /**
* Creates the appropriate subclass of HttpUriRequest for passed in request.
* 请求工厂类{GET,DELET,PUT,POST}
* @param request the request
* @param additionalHeaders the additional headers
* @return the http uri request
* @throws AuthFailureError the auth failure error
*/
@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;
}
default:
throw new IllegalStateException("Unknown request method.");
}
} /**
* Sets the entity if non empty body.
* 非空体Entity
* @param httpRequest the http request
* @param request the request
* @throws AuthFailureError the auth failure error
*/
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>
* 由子类覆写扩展
* @param request the request
* @throws IOException Signals that an I/O exception has occurred.
*/
protected void onPrepareRequest(HttpUriRequest request) throws IOException {
// Nothing.
}
}

它的构造参数是一个HttpClient,Velloy是用AndroidHttpClient.newInstance(userAgent)建立一个HttpClient实例。

再看这个类的最重要方法也就是对HttpStack接口的performRequest()方法进行具体实现。

第一步:通过这个静态方法createHttpRequest()来获取一个HttpUriRequest请求实例,其中HttpGet,HttpPost,HttpPut,HttpDelete都实现了HttpUriRequest这个接口。

这步就确定了请求类型和创立了Http实际请求。

第二步:通过这两个方法添加Http头部,

addHeaders(httpRequest, additionalHeaders);//添加自定义头部
addHeaders(httpRequest, request.getHeaders());//添加请求自带头部

第三步:这个方法

onPrepareRequest()

挺人性化的,相当于AsyncTask的onPreExecute(),不过要实现这个方法需要自行扩展此类,谷歌没有把她提出来。

一开始我还以为没有类似的方法,像Afinal的方法名字取得很吸引人,叫onStart(),onSuccess(),onFailure()。其实在Volley与之相对应的都有,onResponse就相当于onSuccess(),onErrorResponse就相当于onFailure(),而onPrepareRequest()就对应onStart()。

第四步:设置超时,这个超时设置值是在Request里封装进去了,Request封装了很多东西,比如请求的URL等。

在此谷歌在超时这里做了很温馨的提示,设置连接超时考虑WIFI和3G网络设置不一样,这里应该可以留出一个缺口,根据实际网络设置不一样的时常。貌似现在很多应用会根据网络来进行内容排版,例如什么无图模式啊,仅在wifi下上传等。

HurlStack

先看下构造,看来大框架构造都是按这格式的。

 /**
* 默认的构造器
* {@link Volley#newRequestQueue(android.content.Context, HttpStack)}
*/
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//Url转换器
* @param sslSocketFactory SSL factory to use for HTTPS connections//安全连接
*/
public HurlStack(UrlRewriter urlRewriter, SSLSocketFactory sslSocketFactory) {
mUrlRewriter = urlRewriter;
mSslSocketFactory = sslSocketFactory;
}

由此可见主要字段就是mUrlRewriter 和mSslSocketFactory 。前面的是URL转换接口,后面是安全连接。

这个URL转换接口还是挺人性化的,可以过滤些非法字符和省略Http或者www.

 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);
}

然后我们还是看HttpStack接口的performRequest()方法实现。

@Override
public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
throws IOException, AuthFailureError {
String url = request.getUrl();//获取这个请求的url
HashMap<String, String> map = new HashMap<String, String>();
map.putAll(request.getHeaders());
map.putAll(additionalHeaders);
if (mUrlRewriter != null) {//默认的不会对url转换
String rewritten = mUrlRewriter.rewriteUrl(url);//实现UrlRewriter#rewriteUrl方法
if (rewritten == null) {
throw new IOException("URL blocked by rewriter: " + url);
}
url = rewritten;
}
URL parsedUrl = new URL(url);//解析后Url
HttpURLConnection connection = openConnection(parsedUrl, request);
for (String headerName : map.keySet()) {//为connection添加属性
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) {//不能取回ResponseCode
// -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);//通过responseStatus获得一个BasicHttpResponse
response.setEntity(entityFromConnection(connection));//设置Entity
for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {//header
if (header.getKey() != null) {
Header h = new BasicHeader(header.getKey(), header.getValue().get(0));
response.addHeader(h);
}
}
return response;
}

第一步:获取请求地址url,如果写了UrlRewriter就会按照这个接口的规则更改URL。

第二步:建立URL,通过createConnection()方法获得一个HttpURLConnection,通过openConnection()方法设置一些超时类的Http配置,然后添加头部,并且通过setConnectionParametersForRequest()方法设置HttpURLConnection的请求方法(PUT.GET,POST,DELETE...)。

第三步:然后通过HttpURLConnection获取ResponseCode,ResponseMessage,ResponseStatus,BasicHttpResponse响应结果,并进行响应处理。

第四步:通过entityFromConnection(),把HttpURLConnection获得的流转化为HttpEntity,并返回带HttpEntity的HttpResponse。

 /**
* Initializes an {@link HttpEntity} from the given {@link HttpURLConnection}.
* 从HttpURLConnection获取一个HttpEntity
* @param connection
* @return an HttpEntity populated with data from <code>connection</code>.
*/
private static HttpEntity entityFromConnection(HttpURLConnection connection) {
BasicHttpEntity entity = new BasicHttpEntity();
InputStream inputStream;//首先从HttpURLConnection获取一个输入流
try {
inputStream = connection.getInputStream();
} catch (IOException ioe) {
inputStream = connection.getErrorStream();
}
entity.setContent(inputStream);//把流设置为HttpEntity的Content
entity.setContentLength(connection.getContentLength());//设置内容长度
entity.setContentEncoding(connection.getContentEncoding());//设置编码格式
entity.setContentType(connection.getContentType());//设置内容类型
return entity;
}

为什么HurlStack没有onPrepareRequest()方法,如果要的话那就只有知己加了。

来看扩展HttpClientStack的一个类:

public class IpadHttpStack extends  HttpClientStack{

    interface OnStartListener{
void onStart(HttpUriRequest request);
} OnStartListener mOnStartListener;
static String ua = "ipad"; public IpadHttpStack() {
super(AndroidHttpClient.newInstance(ua));
// TODO Auto-generated constructor stub
} @Override
protected void onPrepareRequest(HttpUriRequest request) throws IOException {
// TODO Auto-generated method stub
super.onPrepareRequest(request);
if(mOnStartListener!=null)
mOnStartListener.onStart(request);
} public void setOnStartListener(OnStartListener listener) {
this.mOnStartListener = listener;
} }

这是测试类,访问路由器网关。

public class MainActivity extends Activity {
RequestQueue mQueue;
IpadHttpStack bvinHttp;
private static HashSet<Class<?>> exeptionList = new HashSet<Class<?>>();
static{
exeptionList.add(AuthFailureError.class);
exeptionList.add(NetworkError.class);
exeptionList.add(NoConnectionError.class);
exeptionList.add(ParseError.class);
exeptionList.add(ServerError.class);
exeptionList.add(TimeoutError.class);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.e("onResponse","sdgdsg");
bvinHttp = new IpadHttpStack();
mQueue = Volley.newRequestQueue(getApplicationContext(),bvinHttp);
//StringRequest四个构造参数分别是Request类型,url,网络请求响应监听器,错误监听器
bvinHttp.setOnStartListener(new IpadHttpStack.OnStartListener() { @Override
public void onStart(HttpUriRequest request) {
// TODO Auto-generated method stub }
});
Authenticator.setDefault(new Authenticator() { @Override
protected PasswordAuthentication getPasswordAuthentication() {
// TODO Auto-generated method stub
return new PasswordAuthentication("admin", "admin".toCharArray());
} });
mQueue.add(new StringRequest(Method.GET, "http://192.168.1.1", new Listener<String>(){ @Override
public void onResponse(String arg0) {
// TODO Auto-generated method stub
Log.e("onResponse", arg0);
} }, new ErrorListener(){ @Override
public void onErrorResponse(VolleyError arg0) {
// TODO Auto-generated method stub
if (arg0 instanceof TimeoutError) {
Log.e("onErrorResponse", "超时");
}else if(arg0 instanceof AuthFailureError){
Log.e("AuthFailureError", arg0.toString());
}
Log.e("AuthFailureError", arg0.toString());
//exeptionList.contains(arg0)
} }));
mQueue.start();
} @Override
protected void onStop() {
// TODO Auto-generated method stub
super.onStop();
mQueue.stop();
} @Override
public boolean onCreateOptionsMenu(Menu menu) {
// TODO Auto-generated method stub
menu.add("取消");
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// TODO Auto-generated method stub
mQueue.cancelAll(new RequestFilter(){ @Override
public boolean apply(Request<?> arg0) {
// TODO Auto-generated method stub
arg0.cancel();
return false;
}});
return super.onOptionsItemSelected(item);
} }
 
 

HttpStack及其实现类的更多相关文章

  1. 谷歌Volley网络框架讲解——HttpStack及其实现类

    前两篇已经对网络请求流程已经梳理了个大概,这次我们着重看一下HttpStack和它的其实现类.我们之前在Network篇讲过它仅有一个实现类,而今天我们讲的HttpStack有两个实现类. 其中Htt ...

  2. Java类的继承与多态特性-入门笔记

    相信对于继承和多态的概念性我就不在怎么解释啦!不管你是.Net还是Java面向对象编程都是比不缺少一堂课~~Net如此Java亦也有同样的思想成分包含其中. 继承,多态,封装是Java面向对象的3大特 ...

  3. Volley框架支持HTTPS请求。

    第一次写帖子,嘿嘿. 最近了解到google2013IO大会出了个网络框架,正好项目也需要用到,就看了下. 最后发现接口都是HTTPS的,但是Volley默认是不支持HTTPS,网上找了好久,都没有对 ...

  4. 谷歌Volley网络框架讲解——网络枢纽

    研究了这么久的Volley,愈来愈发现这个框架的精美和人性化.比起民间一些框架强很多,一开始总是盲人摸象找不到头绪,现在终于有些明朗了.Volley其实就是一个请求队列的代理类,我们看下UML. 这就 ...

  5. Java基础学习总结(84)——Java面向对象六大原则和设计模式

    面向对象六大原则 在此之前,有一点需要大家知道,熟悉这些原则并不是说你写出的程序就一定灵活.清晰,只是为你优秀的代码之路铺上了一层栅栏,在这些原则的指导下,你才能避免陷入一些常见的代码泥沼,从而让你写 ...

  6. 谷歌Volley网络框架讲解——BasicNetwork类

    谷歌Volley网络框架讲解——BasicNetwork类 这个类是toolbox工具箱包里的,实现了Network接口. 先来看下Network这个interface,performRequest( ...

  7. 谷歌Volley网络框架讲解——Network及其实现类

    我们看到Network接口只有一个实现类BasicNetwork,而HttpStack有两个实现类. BasicNetwork这个类是toolbox工具箱包里的,实现了Network接口. 先来看下N ...

  8. volley3--Volley类

    Volley这个类,Volley作为整个框架的入口,其实就是创建了一个RequestQueue队列 public class Volley { /** * Default on-disk cache ...

  9. C++ 可配置的类工厂

    项目中常用到工厂模式,工厂模式可以把创建对象的具体细节封装到Create函数中,减少重复代码,增强可读和可维护性.传统的工厂实现如下: class Widget { public: virtual i ...

随机推荐

  1. Postman 是一个非常棒的Chrome扩展,提供功能强大的API & HTTP 请求调试

    Postman 是一个非常棒的Chrome扩展,提供功能强大的API & HTTP 请求调试   需要FQ才能安装,使用时应该不用FQ了,除非使用postman的历史记录功能:   非常棒的C ...

  2. Go as continuous delivery tool for .NET

    http://simon-says-architecture.com/2014/02/28/go-as-continuous-delivery-tool-for-net/ Following my p ...

  3. 进程切换switch_to宏第三个参数分析

    进程切换一般都涉及三个进程,如进程a切换成进程b,b开始执行,但是当a恢复执行的时候往往是通过一个进程c,而不是进程b. 注意switch_to的调用: switch_to(prev,next,pre ...

  4. 聊聊单元測试(一)——EasyMock

    一.单元測试是保证软件质量的重要方法. 单元測试是对系统中某个模块功能的验证,但我们总会遇到这样那样的问题,导致測试代码非常难编写.最直接的一个原因便是强耦合关系,被測试者依赖一些不easy构造,比較 ...

  5. ArcEngine下纵断面图的绘制

    我是採用Dev控件中的画图控件来绘制的纵断面图,以下主要来介绍下输电线路选址以及纵断面图的实时绘制的实现流程. 一.关于输电线路的选址,首先要准备好基础地理数据,包含选线区的DOM,DEM,DLG以及 ...

  6. SSH深度历险记(两) Jboss+EJB一审

    学习感悟:每次学习新知识.通过初审会从小事做起,获得成就感.经典Hello Workd我们成功的例子奠定了门哈,呢.非常好的理解了.Ejb的核心. 今天主要以这个小实例,来学习EJB的分布式,我们能够 ...

  7. Android adb端口转发调试助手Packet Sender

    相信大家做过安卓开发或者安卓自动化测试开发的都离不开adb这个Android Debug Bridge这个工具,该工具有个很重要的功能就是端口转发.比如你在目标安卓机器端建立了一个服务来处理获取当前界 ...

  8. 原生AJAX基础讲解及兼容处理

    原文:原生AJAX基础讲解及兼容处理 AJAX = Asynchronous JavaScript and XML (异步的JavaScript和XML). AJAX不是新技术 ,但却是热门的技术.它 ...

  9. 【iOS】Xib的使用与File&#39;Owner总结

    一.XIB的适用范围 xib(也叫Nib)与storyboard一样是用来描写叙述界面的. storyboard描写叙述的是比較大型的,大范围.适合描写叙述界面跳转等. 二.XIB的使用 Xib是小范 ...

  10. hdu oj1102 Constructing Roads(最小生成树)

    Constructing Roads Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Other ...