Volley源码完全解析之HttpStack

2018-02-06  本文已影响0人  抽象语法树

HttpURLConnection和HttpClient

HttpURLConnection

HttpClient

HttpURLConnection和HttpClient的选择

HttpStack

HttpResponse performRequest(Request<?> var1, Map<String, String> var2) throws IOException, AuthFailureError;

HurlStack

    private static final String HEADER_CONTENT_TYPE = "Content-Type";
    private final HurlStack.UrlRewriter mUrlRewriter;
    private final SSLSocketFactory mSslSocketFactory;

HurlStack的成员变量只有三个,一个是表示“Content-Type”字符串的静态常量,一个URL转换接口,还有一个是生成SSLSocket的工厂类。
至于SSLSocket,它是扩展Socket并提供使用SSL或TLS协议的安全套接字。这种套接字是正常的流套接字,但是它们在基础网络传输协议(如TCP)上添加了安全保护层。

 public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders) throws IOException, AuthFailureError {
        String url = request.getUrl();
        HashMap<String, String> map = new HashMap();
        map.putAll(request.getHeaders());
        map.putAll(additionalHeaders);
        if(this.mUrlRewriter != null) {
            String rewritten = this.mUrlRewriter.rewriteUrl(url);
            if(rewritten == null) {
                throw new IOException("URL blocked by rewriter: " + url);
            }

            url = rewritten;
        }

        URL parsedUrl = new URL(url);
        HttpURLConnection connection = this.openConnection(parsedUrl, request);
        Iterator var8 = map.keySet().iterator();

        while(var8.hasNext()) {
            String headerName = (String)var8.next();
            connection.addRequestProperty(headerName, (String)map.get(headerName));
        }

        setConnectionParametersForRequest(connection, request);
        ProtocolVersion protocolVersion = new ProtocolVersion("HTTP", 1, 1);
        int responseCode = connection.getResponseCode();
        if(responseCode == -1) {
            throw new IOException("Could not retrieve response code from HttpUrlConnection.");
        } else {
            StatusLine responseStatus = new BasicStatusLine(protocolVersion, connection.getResponseCode(), connection.getResponseMessage());
            BasicHttpResponse response = new BasicHttpResponse(responseStatus);
            response.setEntity(entityFromConnection(connection));
            Iterator var12 = connection.getHeaderFields().entrySet().iterator();

            while(var12.hasNext()) {
                Entry<String, List<String>> header = (Entry)var12.next();
                if(header.getKey() != null) {
                    Header h = new BasicHeader((String)header.getKey(), (String)((List)header.getValue()).get(0));
                    response.addHeader(h);
                }
            }

            return response;
        }
    }

首先这个方法将请求的参数信息全部整合放在一个map里,然后通过判断mUrlRewriter是否为空来决定是否转换URL,我们可以通过实现mUrlRewriter类去扩展Volley从而实现过滤非法字符之类的操作。
接着,这个方法通过openConnection方法打开了一个TCP连接,并配置连接的相关信息,如超时时间,是否采用缓存等,并且如果是采用HTTP协议,则会为其设置默认的SSLSocketFactory(当然是在SSLSocketFactory不为空的情况下),需要注意的是,现在只是打开了一个TCP连接,并没有实际发送http请求。
openConnection:

    private HttpURLConnection openConnection(URL url, Request<?> request) throws IOException {
        HttpURLConnection connection = this.createConnection(url);
        int timeoutMs = request.getTimeoutMs();
        connection.setConnectTimeout(timeoutMs);
        connection.setReadTimeout(timeoutMs);
        connection.setUseCaches(false);
        connection.setDoInput(true);
        if("https".equals(url.getProtocol()) && this.mSslSocketFactory != null) {
            ((HttpsURLConnection)connection).setSSLSocketFactory(this.mSslSocketFactory);
        }

        return connection;
    }

再接下来,就是配置http的请求头信息了,通过遍历存放着所有参数信息的map,再调用addRequestProperty将信息加入http的请求头。
而setConnectionParametersForRequest方法的作用则是根据request的请求类型来设置connection的请求类型,如果是POST或者PUT的话还需要将发送的内容输出到并且设置相应的content-type。
setConnectionParametersForRequest:

static void setConnectionParametersForRequest(HttpURLConnection connection, Request<?> request) throws IOException, AuthFailureError {
        switch(request.getMethod()) {
        case -1:
            byte[] postBody = request.getPostBody();
            if(postBody != null) {
                connection.setDoOutput(true);
                connection.setRequestMethod("POST");
                connection.addRequestProperty("Content-Type", request.getPostBodyContentType());
                DataOutputStream out = new DataOutputStream(connection.getOutputStream());
                out.write(postBody);
                out.close();
            }
            break;
        case 0:
            connection.setRequestMethod("GET");
            break;
          .....

再接着就是设置协议的类型以及版本,然后构造一个BasicHttpResponse封装本次的响应的信息。其中包含了响应的头部信息和内容,返回给调用该方法的上级进行进一步的解析。(其真正解析成我们需要的数据是在Request的子类中,如StringRequest类中)。

HttpClientStack

    protected final HttpClient mClient;
    private static final String HEADER_CONTENT_TYPE = "Content-Type";

很简单,只有一个HttpClient对象和一个字符串常量。其中HttpClient对象在初始化时传入,也就是在VOLLEY类的newRequestQueue方法中通过AndroidHttpClient.newInstance(userAgent)方法取得。而AndroidHttpClient则是实现了HttpClient接口的类,主要是帮我们做了一些缺省的配置,如连接超时和socket超时都是设置为20秒,连接管理器设置为ThreadSafeClientConnManager。

    public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders) throws IOException, AuthFailureError {
        HttpUriRequest httpRequest = createHttpRequest(request, additionalHeaders);
        addHeaders(httpRequest, additionalHeaders);
        addHeaders(httpRequest, request.getHeaders());
        this.onPrepareRequest(httpRequest);
        HttpParams httpParams = httpRequest.getParams();
        int timeoutMs = request.getTimeoutMs();
        HttpConnectionParams.setConnectionTimeout(httpParams, 5000);
        HttpConnectionParams.setSoTimeout(httpParams, timeoutMs);
        return this.mClient.execute(httpRequest);
    }

首先通过createHttpRequest()方法,根据请求的类型产生一个网络请求,这里跟HurlStack里的处理类似。接着配置头部信息,加入请求的参数,设置超时时长,最后再通过mClient执行请求。

总结

上一篇 下一篇

猜你喜欢

热点阅读