Volley的框架解读一(Http的封装)

来源:互联网 发布:黑客查看网站php源码 编辑:程序博客网 时间:2024/06/05 16:26

先瞄瞄UML类图

httpstack

 

 

在Volley中真正的网络请求是由HttpStack定义的,这是一个接口,它唯一的一个方法就是执行网路请求获取响应。而HttpClientStack和HurlStack是该接口的实现类,对应不同的网络请求的底层实现,HttpClientStack是基于HttpClient的,HurlStack是基于HttpURLConnection的。

先看看这个父接口(HttpStack)

源码解读绝招一:看父类,接口,这样你才知道这个类是干啥的,应该有什么行为
/** * Volley中真正去执行联网的类,返回的信息封装成HttpResponse */public interface HttpStack {    /**     *  真正去执行联网的方法     */    public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)        throws IOException, AuthFailureError;}

Volley本来是支持HttpURLConnection,还有HttpClient的,当然处于现在这个年代,HttpClient被废弃了,所以只看HttpURLConnection的封装

另外说一点Volley中的Request,从字面理解上是请求,但是其实不是一个真正的网络请求,个人理解为是对真正的网络请求的各个属性的描述。

HttpStack是真正的网络请求,Request则是封装了超时时间、请求方式、参数、url等网络请求所必须的参数。通过变换不同的属性参数(最基本的如请求方式GET POST),可以获取不同的网络请求。

OK,现在在说下我对于HttpClientStack和HurlStack的理解,二者的工作思路是这样的:

1. 首先从Volley的Request内获取各个属性、如超时间、请求方式、参数和url2.创建网络请求,HttpClientStack是创建HttpClient ,HurlStack是创建HttpURLConnection3.对网络请求设置各个属性参数4.定义执行网路请求的方法,并获取响应,将响应返回出去

上面说的是思路,现在看一下源码细节是怎么写的,一些得从performRequest开始

源码细节performRequest

@Override    public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)            throws IOException, AuthFailureError {        String url = request.getUrl();        HashMap<String, String> map = new HashMap<String, String>();        map.putAll(request.getHeaders());        map.putAll(additionalHeaders);        if (mUrlRewriter != null) {            String rewritten = mUrlRewriter.rewriteUrl(url);            if (rewritten == null) {                throw new IOException("URL blocked by rewriter: " + url);            }            url = rewritten;        }        URL parsedUrl = new URL(url);        //1.得到一个HttpURLConnection        HttpURLConnection connection = openConnection(parsedUrl, request);        //2.设置响应头        for (String headerName : map.keySet()) {            connection.addRequestProperty(headerName, map.get(headerName));        }        //3.设置请求方式        setConnectionParametersForRequest(connection, request);        //4.响应的协议版本        ProtocolVersion protocolVersion = new ProtocolVersion("HTTP", 1, 1);        //5.获取状态码        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.");        }        //6.根据链接获取响应的状态码响应信息        StatusLine responseStatus = new BasicStatusLine(protocolVersion,                connection.getResponseCode(), connection.getResponseMessage());        //创建响应        BasicHttpResponse response = new BasicHttpResponse(responseStatus);        //给响应设置响应体,响应体来自于链接        response.setEntity(entityFromConnection(connection));        //将得到的头信息赋值给实体类(BasicHttpResponse)        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;    }

看传入参数Request,里面有设置了很多http的属性,如超时,是否缓存,还有一个参数设置头信息

再看看其中几个重要方法

  • openConnection
  • setConnectionParametersForRequest 设置请求方式
  • entityFromConnection

openConnection封装细节

   /**     * 设置HttpURLConnection 一些参数以及支持https     * @param url     * @return an open connection     * @throws IOException     */    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;    }

没啥好说的就是创建了HttpURLConnection,设置一些属性

entityFromConnection封装细节

  /**     * 将connection得到的信息封装成实体(BasicHttpEntity)返回     * @param connection     * @return     */    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;    }

这里就是从HttpURLConnection获取接口信息,封装成HttpEntity,返回给调用者BasicNetWork

Volley的真正的网络请求就是这些了,注意这里是定义网络请求和网络请求的方法,但是调用执行网络请求其实是在NetWork接口及其实现类BasicNetwork内。

如果对于HttpURLConnection 不太了解,或者忘记的差不对了可以看看我前面文章

Volley的框架解读准备一HttpURLConnection