android网络框架volley学习之HttpStack接口

    这篇博文将介绍Volley框架的实际网络访问类HurlStack和HttpClientStack.这两个类均实现了HttpStack接口,只是采用了不同的网络访问类。HurlStack类是利用通过URL打开httpURLconnection网络通信连接,实现了网络访问。而HttpClientStack则是利用android中org.apache.http系列的开发包实现网络访问,实现过程较为简单。这两个类都是是Volley进行网络访问的实际类。

    下面逐个查看这两个类的代码

HurlStack类

//利用httpURLconnection建立一个httpStack
public class HurlStack implements HttpStack {

    private static final String HEADER_CONTENT_TYPE = "Content-Type";
  
    //接口用于重新书写URL
    public interface UrlRewriter {
        public String rewriteUrl(String originalUrl);
    }

    private final UrlRewriter mUrlRewriter;

    public HurlStack() {
        this(null);
    }

    public HurlStack(UrlRewriter urlRewriter) {
        this(urlRewriter, null);
    }

    public HurlStack(UrlRewriter urlRewriter, SSLSocketFactory sslSocketFactory) {
        mUrlRewriter = urlRewriter;
        mSslSocketFactory = sslSocketFactory;
    }
     //实现未实现的方法
    @Override
    public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
            throws IOException, AuthFailureError {
	//获取请求体中的URL
        String url = request.getUrl();
	//建立一个map用于存放请求头信息
        HashMap<String, String> map = new HashMap<String, String>();
	//将原来请求体中的请求头添加到map中
        map.putAll(request.getHeaders());
	//添加额外的请求头
        map.putAll(additionalHeaders);
	//如果mUrlRewriter不为空则重写URL
        if (mUrlRewriter != null) {
            String rewritten = mUrlRewriter.rewriteUrl(url);
            if (rewritten == null) {
                throw new IOException("URL blocked by rewriter: " + url);
            }
            url = rewritten;
        }

	//通过String建立URL对象
        URL parsedUrl = new URL(url);

	//打开http通信链接
        HttpURLConnection connection = openConnection(parsedUrl, request);

	//为通信连接添加请求头
        for (String headerName : map.keySet()) {
            connection.addRequestProperty(headerName, map.get(headerName));
        }

	//设置通信链接的参数
        setConnectionParametersForRequest(connection, request);

        /* 用请求回来的响应来构造HTTPResponse对象
         *1、建立协议控制版本的对象。
         *2、利用协议版本对象构建响应行对象。
         *3、构建HTTPResponse对象。
        **/
        ProtocolVersion protocolVersion = new ProtocolVersion("HTTP", 1, 1);
        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.");
        }
        StatusLine responseStatus = new BasicStatusLine(protocolVersion,
                connection.getResponseCode(), connection.getResponseMessage());
        BasicHttpResponse response = new BasicHttpResponse(responseStatus);
        //为HTTPResponse添加实体
        response.setEntity(entityFromConnection(connection));
        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;
    }
   //从通信连接中获取流对象并构建实体。
    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;
    }
    //建立http通信链接
    protected HttpURLConnection createConnection(URL url) throws IOException {
        return (HttpURLConnection) url.openConnection();
    }
    //建立通信链接同时为通信链接设置一些基本参数
    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;
    }
        //根据请求体的方法 对通信链接的参数进行设置
	static void setConnectionParametersForRequest(HttpURLConnection connection,
            Request<?> request) throws IOException, AuthFailureError {
        switch (request.getMethod()) {
            case Method.GET:
                //这里其实不需要设置get方法,因为connection默认的就是get方法
                connection.setRequestMethod("GET");
                break;
            case Method.POST:
                connection.setRequestMethod("POST");
                addBodyIfExists(connection, request);
                break;
        }
    }
     //如果是post方法则添加请求体
    private static void addBodyIfExists(HttpURLConnection connection, Request<?> request)
            throws IOException, AuthFailureError {
        byte[] body = request.getBody();
        if (body != null) {
            connection.setDoOutput(true);//设置允许输出
            connection.addRequestProperty(HEADER_CONTENT_TYPE, request.getBodyContentType());
            DataOutputStream out = new DataOutputStream(connection.getOutputStream());
            out.write(body);
            out.close();
        }
    }
}

整个网络访问和生成httpResponse对象的步骤基本可以概括为:

    1、通过URL建立网络通信连接得到httpURLconnection对象。

    2、对httpURLconnection对象进行一系列的设置,包括方法、请求头、以及访问链接超时等,如果是post请求则需要设置httpURLconnection的输出为true,接着用流的形式写入到请求体中。

    3、建立协议控制版本的对象,同时利用协议版本对象构建响应行对象最终生成HTTPResponse对象。

    4、为生成的HTTPResponse对象(通过httpURLconnection对象)添加实体和响应头。

HttpClientStack类

public class HttpClientStack implements HttpStack {
    
    //请求的客户端
    protected final HttpClient mClient;

    //内容类型的头
    private final static String HEADER_CONTENT_TYPE = "Content-Type";
	
    //构造函数 
    public HttpClientStack(HttpClient client) {
        mClient = client;
    }
    //添加头信息
    private static void addHeaders(HttpUriRequest httpRequest, Map<String, String> headers) {
        for (String key : headers.keySet()) {
            httpRequest.setHeader(key, headers.get(key));
        }
    }
    //将map形式的请求参数转化成NameValuePair对象存储在list集合中
    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;
    }

    @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());//添加从request中获取的请求头
        HttpParams httpParams = httpRequest.getParams();//获取请求的参数的引用
        int timeoutMs = request.getTimeoutMs();
        //通过HttpConnectionParams的静态方法对httpParams的一些参数进行设置
        HttpConnectionParams.setConnectionTimeout(httpParams, 5000);
        HttpConnectionParams.setSoTimeout(httpParams, timeoutMs);
        return mClient.execute(httpRequest);//执行请求同时返回HTTPResponse对象
    }

    //根据request对象的方法建立不同的请求报文
    static HttpUriRequest createHttpRequest(Request<?> request,
            Map<String, String> additionalHeaders) throws AuthFailureError {
        switch (request.getMethod()) {
            //创建get请求httpGet
            case Method.GET:
                return new HttpGet(request.getUrl());
            //创建post请求httpPost
            case Method.POST: {
                HttpPost postRequest = new HttpPost(request.getUrl());
                postRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType());
                setEntityIfNonEmptyBody(postRequest, request);
                return postRequest;
            }
        }
    }
    //为post请求添加实体
    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);
        }
    }
}

HttpClientStack生成httpResponse的过程如下:

    1、建立httpclient,android中实现的类有DefaultHttpClient和AndroidHttpClient。

    2、根据request的方法创建不同的请求报文(post请求需要添加实体)。

    3、为请求添加请求头同时设置一些参数信息。

    4、调用httpclient的execute方法执行请求,生成httpResponse对象并返回。


    以上就基于httpStack接口的两个最真实的网络访问类的实现过程。前面也是多次提到在什么情况使用HurlStack类喝HttpClientStack类,这里就不说明了。

   不对之处,请大家指正,谢谢!

你可能感兴趣的:(android,框架,网络通信,Volley)