Quantcast
Channel: CSDN博客移动开发推荐文章
Viewing all articles
Browse latest Browse all 5930

【androidx86 5.1.1】Android HttpClient请求过程解析(上)

$
0
0

Android HttpClient请求过程解析

前言:很久没有写源码解析相关的文章了,所谓“三天不写,上房揭瓦”,这都仨月啦!前段时间忙着发版,经理有别的事情忙,就把管理发版的事情丢给我了,这事确实很麻烦啊,要关注的人事物都很多,虽然对于技术的提升很小,不过也加深了我对整个产品的理解和视野的开阔,对于时间安排与发展规划都有了更深的理解。每次的前言都是自己胡说八道的废话。好了,言归正传,这次的博客就是对于androidHttpClient进行请求数据的流程解析。

 

综述

总体来说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);

}

没啥可说的,首先判断了requestnull异常,就再次进行了内部跳转,其中有一个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、 执行RequestDirectorexecute函数,相关代码文件位于src\org\apache\http\client\ RequestDirector.java

实际上调用了DefaultRequestDirectorexecute函数,其位置位于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、未完待续

 

作者:class_brick 发表于2017/9/18 21:37:51 原文链接
阅读:76 评论:0 查看评论

Viewing all articles
Browse latest Browse all 5930

Trending Articles