HttpStack及其实现类
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及其实现类的更多相关文章
- 谷歌Volley网络框架讲解——HttpStack及其实现类
前两篇已经对网络请求流程已经梳理了个大概,这次我们着重看一下HttpStack和它的其实现类.我们之前在Network篇讲过它仅有一个实现类,而今天我们讲的HttpStack有两个实现类. 其中Htt ...
- Java类的继承与多态特性-入门笔记
相信对于继承和多态的概念性我就不在怎么解释啦!不管你是.Net还是Java面向对象编程都是比不缺少一堂课~~Net如此Java亦也有同样的思想成分包含其中. 继承,多态,封装是Java面向对象的3大特 ...
- Volley框架支持HTTPS请求。
第一次写帖子,嘿嘿. 最近了解到google2013IO大会出了个网络框架,正好项目也需要用到,就看了下. 最后发现接口都是HTTPS的,但是Volley默认是不支持HTTPS,网上找了好久,都没有对 ...
- 谷歌Volley网络框架讲解——网络枢纽
研究了这么久的Volley,愈来愈发现这个框架的精美和人性化.比起民间一些框架强很多,一开始总是盲人摸象找不到头绪,现在终于有些明朗了.Volley其实就是一个请求队列的代理类,我们看下UML. 这就 ...
- Java基础学习总结(84)——Java面向对象六大原则和设计模式
面向对象六大原则 在此之前,有一点需要大家知道,熟悉这些原则并不是说你写出的程序就一定灵活.清晰,只是为你优秀的代码之路铺上了一层栅栏,在这些原则的指导下,你才能避免陷入一些常见的代码泥沼,从而让你写 ...
- 谷歌Volley网络框架讲解——BasicNetwork类
谷歌Volley网络框架讲解——BasicNetwork类 这个类是toolbox工具箱包里的,实现了Network接口. 先来看下Network这个interface,performRequest( ...
- 谷歌Volley网络框架讲解——Network及其实现类
我们看到Network接口只有一个实现类BasicNetwork,而HttpStack有两个实现类. BasicNetwork这个类是toolbox工具箱包里的,实现了Network接口. 先来看下N ...
- volley3--Volley类
Volley这个类,Volley作为整个框架的入口,其实就是创建了一个RequestQueue队列 public class Volley { /** * Default on-disk cache ...
- C++ 可配置的类工厂
项目中常用到工厂模式,工厂模式可以把创建对象的具体细节封装到Create函数中,减少重复代码,增强可读和可维护性.传统的工厂实现如下: class Widget { public: virtual i ...
随机推荐
- HDU 1102 Constructing Roads, Prim+优先队列
题目链接:HDU 1102 Constructing Roads Constructing Roads Problem Description There are N villages, which ...
- Windows平台配置Appium+Java环境
1) 安装JDK 下载地址:http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 安装 ...
- VS2012使用XListCtrl
XListCtrl.强大ListCtrl.到现在,所有我曾经遇到过ListCtrl我们使用XListCtrl攻克. XListCtrl有什么可以支持? 变化column背景颜色.尺寸.线.制作chec ...
- nginx 查看并发连接数
这里仅仅说一下用命令查看(也可配置页面) 通过查tcp连接数 1.netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]} ...
- Hadoop -YARN 应用程序设计概述
一概述 应用程序是用户编写的处理数据的统称,它从YARN中申请资源完毕自己的计算任务.YARN自身相应用程序类型没有不论什么限制,它能够是处理短类型任务的MapReduce作业,也能够是 ...
- QT添加exe文件的图标LOGO
首先你需要一个ICO文件,这样的一个: 使用百度搜索到的在线工具直接生成一个ICO文件保存到本地就可以了 将这人LOGO.ico文件保存到自己的resource文件夹下 然后在工程中新建一个qrc文件 ...
- Ora创建job定时执行某存储过程
--创建job任务,每天晚上8点执行存储过程:por_postrecords-- declare job number; begin sys.dbms_job.submit(job =>job, ...
- 开源文档管理系统LogicalDOC测试报告---安装篇
开源文档管理系统LogicalDOC测试报告---安装篇 分类: Linux2011-06-22 15:40 7436人阅读 评论(3) 收藏 举报 文档管理测试mysql数据库installerja ...
- Android项目--XML解析
对于xml文件,一般有两种解析方式: -----pull解析-------- -----Sax解析------- 如果xml文件是本地文件,那么就好说了 AssetManager assetManag ...
- Android中常用的颜色
代码: <?xml version=”″ ?> <resources> <color name=”white”>#ffffff</color><! ...