【androidx86 5.1.1】Android HttpClient请求过程解析(上)
来源:互联网 发布:冒险岛伴侣官方域名 编辑:程序博客网 时间:2024/06/06 02:23
Android HttpClient请求过程解析
前言:很久没有写源码解析相关的文章了,所谓“三天不写,上房揭瓦”,这都仨月啦!前段时间忙着发版,经理有别的事情忙,就把管理发版的事情丢给我了,这事确实很麻烦啊,要关注的人事物都很多,虽然对于技术的提升很小,不过也加深了我对整个产品的理解和视野的开阔,对于时间安排与发展规划都有了更深的理解。每次的前言都是自己胡说八道的废话。好了,言归正传,这次的博客就是对于android的HttpClient进行请求数据的流程解析。
综述
总体来说http请求包括三个步骤,分别是域名解析、建立连接、发送请求。
首先写一个简单的HttpClient请求的android代码。
HttpClienthttpClient = new DefaultHttpClient();//1、获取默认客户端
HttpGethttpGet = new HttpGet(“http://www.baidu.com/”); //2、创建HttpGet请求
try{
HttpResponseresponse = httpClient.execute(httpGet);//3、通过客户端发送请求获取数据
}catch (Exception e) {
e.printStackTrace();
}
二、获取默认客户端
首先创建了一个默认的httpClient,其中的调用流程如下:
1、创建DefaultHttpClient对象,其代码位于external\apache-http\src\org\apache\http\impl\client\DefaultHttpClient.java
public DefaultHttpClient() {
super(null,null);
}
2、调用父类,进行构造函数,代码位于external\apache-http\src\org\apache\http\impl\client\AbstractHttpClient.java
/**
* Creates a new HTTP client.
*
* @param conman the connectionmanager
* @param params the parameters
*/
protected AbstractHttpClient(
final ClientConnectionManager conman,
final HttpParams params) {
defaultParams = params;
connManager = conman;
} // constructor
好的,这里构造了一个空的HttpClient对象
三、创建HttpGet请求
然后创建了一个HttpGet请求,其中的调用流程如下:
1、创建HttpGet对象,其代码位于external\apache-http\src\org\apache\http\client\methods\HttpGet.java
/**
* @throws IllegalArgumentException if theuri is invalid.
*/
public HttpGet(final String uri) {
super();
setURI(URI.create(uri));
}
2、父类位于external\apache-http\src\org\apache\http\client\methods\HttpRequestBase.java
public HttpRequestBase() {
super();
this.abortLock =new ReentrantLock();
}
3、父类的父类位于external\apache-http\src\org\apache\http\message\AbstractHttpMessage.java
protected AbstractHttpMessage(finalHttpParams params) {
super();
this.headergroup = new HeaderGroup();
this.params = params;
}
protected AbstractHttpMessage() {
this(null);
}
四、通过客户端发送请求获取数据
放流程图
然后开始正式的解析并获取数据
1、执行我们看到的execute函数,其代码位于src\org\apache\http\impl\client\AbstractHttpClient.java’
其通过两次调用重载的重名函数,跳到了
publicfinal HttpResponse execute(HttpUriRequest request,
HttpContext context)
throws IOException, ClientProtocolException {
if (request == null) {
throw new IllegalArgumentException
("Request must not benull.");
}
returnexecute(determineTarget(request), request, context);
}
没啥可说的,首先判断了request的null异常,就再次进行了内部跳转,其中有一个determineTarget函数
private HttpHostdetermineTarget(HttpUriRequest request) {
// A null target may be acceptable ifthere is a default target.
// Otherwise, the null target isdetected in the director.
HttpHost target = null;
URI requestURI = request.getURI();
//如果URI可以获取到请求类型,则直接新建HttpHost
if (requestURI.isAbsolute()) {
target = new HttpHost(
requestURI.getHost(),
requestURI.getPort(),
requestURI.getScheme());
}
return target;
}
2、接下来依然是调用了不同参数的execute函数
// non-javadoc,see interface HttpClient
public final HttpResponse execute(HttpHosttarget, HttpRequest request,
HttpContext context)
throws IOException,ClientProtocolException {
if (request == null) {
throw new IllegalArgumentException
("Request must not benull.");
}
// a null target may be acceptable,this depends on the route planner
// a null context is acceptable,default context created below
HttpContext execContext = null;
RequestDirector director = null;
// Initialize the request executioncontext making copies of
// all shared objects that arepotentially threading unsafe.
synchronized (this) {
HttpContext defaultContext =createHttpContext();
if (context == null) {
execContext = defaultContext;
} else {
execContext = newDefaultedHttpContext(context, defaultContext);
}
// Create a director for thisrequest
director =createClientRequestDirector(
getRequestExecutor(),
getConnectionManager(),
getConnectionReuseStrategy(),
getConnectionKeepAliveStrategy(),
getRoutePlanner(),
getHttpProcessor().copy(),
getHttpRequestRetryHandler(),
getRedirectHandler(),
getTargetAuthenticationHandler(),
getProxyAuthenticationHandler(),
getUserTokenHandler(),
determineParams(request));
}
try {
return director.execute(target,request, execContext);
} catch(HttpException httpException) {
throw newClientProtocolException(httpException);
}
} // execute
这个函数比较长,其实主要也就三步,第一步创建一个http信息上下文HttpContext,第二步创建一个对于请求的操作者RequestDirector,第三部通过RequestDirector执行请求。RequestDirector的参数比较多,这里先不一一分析,将他的create函数放上来:
protectedRequestDirector createClientRequestDirector(
final HttpRequestExecutor requestExec,
final ClientConnectionManager conman,
final ConnectionReuseStrategy reustrat,
final ConnectionKeepAliveStrategy kastrat,
final HttpRoutePlanner rouplan,
final HttpProcessor httpProcessor,
final HttpRequestRetryHandler retryHandler,
final RedirectHandler redirectHandler,
final AuthenticationHandlertargetAuthHandler,
final AuthenticationHandler proxyAuthHandler,
final UserTokenHandler stateHandler,
final HttpParams params) {
return new DefaultRequestDirector(
requestExec,
conman,
reustrat,
kastrat,
rouplan,
httpProcessor,
retryHandler,
redirectHandler,
targetAuthHandler,
proxyAuthHandler,
stateHandler,
params);
}
3、执行RequestDirector的execute函数,相关代码文件位于src\org\apache\http\client\ RequestDirector.java
实际上调用了DefaultRequestDirector的execute函数,其位置位于src\org\apache\http\impl\client\DefaultRequestDirector.java
首先贴出代码,非常巨大的一个函数:
// non-javadoc, see interfaceClientRequestDirector
public HttpResponse execute(HttpHosttarget, HttpRequest request,
HttpContextcontext)
throws HttpException, IOException {
HttpRequest orig = request;
//打包请求
RequestWrapper origWrapper = wrapRequest(orig);
//设置参数
origWrapper.setParams(params);
//路由定向,不管是做为本地路由还是中转路由
HttpRoute origRoute =determineRoute(target, origWrapper, context);
RoutedRequest roureq = newRoutedRequest(origWrapper, origRoute);
long timeout =ConnManagerParams.getTimeout(params);
int execCount = 0;
boolean reuse = false;
HttpResponse response = null;
boolean done = false;
try {
while (!done) {
// In this loop, theRoutedRequest may be replaced by a
// followup request and route.The request and route passed
// in the method arguments willbe replaced. The original
// request is still availablein 'orig'.
RequestWrapper wrapper =roureq.getRequest();
HttpRoute route =roureq.getRoute();
// See if we have a user tokenbound to the execution context
Object userToken = context.getAttribute(ClientContext.USER_TOKEN);
// Allocate connection ifneeded
if (managedConn == null) {
ClientConnectionRequestconnRequest = connManager.requestConnection(
route, userToken);
if (orig instanceofAbortableHttpRequest) {
((AbortableHttpRequest)orig).setConnectionRequest(connRequest);
}
try {
managedConn =connRequest.getConnection(timeout, TimeUnit.MILLISECONDS);
}catch(InterruptedException interrupted) {
InterruptedIOExceptioniox = new InterruptedIOException();
iox.initCause(interrupted);
throw iox;
}
//如果提交检查前需要测试是否可用,则在android当中先关闭连接
if(HttpConnectionParams.isStaleCheckingEnabled(params)) {
// validate connection
this.log.debug("Stale connection check");
if(managedConn.isStale()) {
this.log.debug("Stale connection detected");
// BEGINandroid-changed
try {
managedConn.close();
} catch(IOException ignored) {
// SSLSocket'swill throw IOException
// because theycan't send a "close
// notify"protocol message to the
// server. Justsupresss any
// exceptionsrelated to closing the
// stale connection.
}
// ENDandroid-changed
}
}
}
if (orig instanceofAbortableHttpRequest) {
((AbortableHttpRequest)orig).setReleaseTrigger(managedConn);
}
// Reopen connection if needed
if (!managedConn.isOpen()) {
managedConn.open(route,context, params);
}
// BEGIN android-added
else {
// b/3241899 set the perrequest timeout parameter on reused connections
managedConn.setSocketTimeout(HttpConnectionParams.getSoTimeout(params));
}
// END android-added
try {
//建立路由跳转连接
establishRoute(route,context);
} catch (TunnelRefusedExceptionex) {
if(this.log.isDebugEnabled()) {
this.log.debug(ex.getMessage());
}
response =ex.getResponse();
break;
}
// Reset headers on the requestwrapper
wrapper.resetHeaders();
// Re-write request URI ifneeded
rewriteRequestURI(wrapper,route);
// Use virtual host if set
target = (HttpHost)wrapper.getParams().getParameter(
ClientPNames.VIRTUAL_HOST);
if (target == null) {
target =route.getTargetHost();
}
HttpHost proxy =route.getProxyHost();
// Populate the executioncontext
context.setAttribute(ExecutionContext.HTTP_TARGET_HOST,
target);
context.setAttribute(ExecutionContext.HTTP_PROXY_HOST,
proxy);
context.setAttribute(ExecutionContext.HTTP_CONNECTION,
managedConn);
context.setAttribute(ClientContext.TARGET_AUTH_STATE,
targetAuthState);
context.setAttribute(ClientContext.PROXY_AUTH_STATE,
proxyAuthState);
// Run request protocolinterceptors
requestExec.preProcess(wrapper,httpProcessor, context);
context.setAttribute(ExecutionContext.HTTP_REQUEST,
wrapper);
boolean retrying = true;
while (retrying) {
// Increment total execcount (with redirects)
execCount++;
// Increment exec count forthis particular request
wrapper.incrementExecCount();
if (wrapper.getExecCount()> 1 && !wrapper.isRepeatable()) {
throw newNonRepeatableRequestException("Cannot retry request " +
"with anon-repeatable request entity");
}
try {
if(this.log.isDebugEnabled()) {
this.log.debug("Attempt " + execCount + " to executerequest");
}
//执行请求
response =requestExec.execute(wrapper, managedConn, context);
retrying = false;
} catch (IOException ex) {
this.log.debug("Closing the connection.");
managedConn.close();
if(retryHandler.retryRequest(ex, execCount, context)) {
if(this.log.isInfoEnabled()) {
this.log.info("I/O exception ("+ ex.getClass().getName() +
")caught when processing request: "
+ ex.getMessage());
}
if(this.log.isDebugEnabled()) {
this.log.debug(ex.getMessage(), ex);
}
this.log.info("Retryingrequest");
} else {
throw ex;
}
// If we have a directroute to the target host
// just re-open connectionand re-try the request
if (route.getHopCount()== 1) {
this.log.debug("Reopening the direct connection.");
managedConn.open(route, context, params);
} else {
// otherwise giveup
throw ex;
}
}
}
// Run response protocol interceptors
response.setParams(params);
requestExec.postProcess(response, httpProcessor, context);
// The connection is in or canbe brought to a re-usable state.
// 是否是一个长连接
reuse = reuseStrategy.keepAlive(response,context);
if(reuse) {
// Set the idle duration ofthis connection
long duration =keepAliveStrategy.getKeepAliveDuration(response, context);
managedConn.setIdleDuration(duration,TimeUnit.MILLISECONDS);
}
RoutedRequest followup =handleResponse(roureq, response, context);
if (followup == null) {
done = true;
} else {
if (reuse) {
this.log.debug("Connection kept alive");
// Make sure theresponse body is fully consumed, if present
HttpEntity entity =response.getEntity();
if (entity != null) {
entity.consumeContent();
}
// entity consumedabove is not an auto-release entity,
// need to mark theconnection re-usable explicitly
managedConn.markReusable();
} else {
managedConn.close();
}
// check if we can use the same connectionfor the followup
if(!followup.getRoute().equals(roureq.getRoute())) {
releaseConnection();
}
roureq = followup;
}
userToken =this.userTokenHandler.getUserToken(context);
context.setAttribute(ClientContext.USER_TOKEN, userToken);
if (managedConn != null) {
managedConn.setState(userToken);
}
} // while not done
// check for entity, releaseconnection if possible
if ((response == null) ||(response.getEntity() == null) ||
!response.getEntity().isStreaming()) {
// connection not needed and(assumed to be) in re-usable state
if (reuse)
managedConn.markReusable();
releaseConnection();
} else {
// install an auto-release entity
HttpEntity entity =response.getEntity();
entity = newBasicManagedEntity(entity, managedConn, reuse);
response.setEntity(entity);
}
return response;
} catch (HttpException ex) {
abortConnection();
throw ex;
} catch (IOException ex) {
abortConnection();
throw ex;
} catch (RuntimeException ex) {
abortConnection();
throw ex;
}
} // execute
4、未完待续
- 【androidx86 5.1.1】Android HttpClient请求过程解析(上)
- 【androidx86 5.1.1】Android HttpClient请求过程解析(下)
- Android中HttpClient请求https的验证过程
- android通过httpClient请求获取JSON数据并且解析
- android通过httpClient请求获取JSON数据并且解析
- Android使用HttpClient请求网络上的数据
- android的HttpClient请求
- Android httpclient 请求
- android---httpclient get请求
- HttpClient请求网络 xml解析
- android HttpClient Http请求 验证
- Android 实现 HttpClient 请求Https
- Android HTTP请求方式:HttpClient
- android中的HttpClient,Delete请求
- Android HTTP请求方式:HttpClient
- Android 之 HttpClient 网络请求
- Android 中HttpClient请求和HttpURLConnect请求
- httpclient请求数据和gson的解析
- Buildings
- 截取URL参数
- 用python实现将数组元素按从小到大的顺序排列
- 机器学习相关材料和网站
- tp5 ThinkPhp5 自定义异常处理类(先留坑
- 【androidx86 5.1.1】Android HttpClient请求过程解析(上)
- jd手机信息爬虫
- 函数调用模型
- Linux jdk的安装
- static关键字
- 第一章 导言 【C程序设计语言 第2版】
- 一点杂感
- 成功人士的3个好习惯
- HDU