网络层架构设计与实战十四错误码和重连功能设计与实现


一、注解



1、重连和重试

在进行网络连接的时候,有可能出现网络连接出错的情况,一般的做法都是重新去尝试,网络框架也是可以对这些进行处理的,如果认为某些接口是比较重要的,可以进行一些重试。重试的话可能有一些最大的连接次数,因为它不可能是无限的重试,如果无限地重试可能导致堆栈的溢出。最大的重试次数需要开发者自己去指定,重连的功能在网络框架中如何去设计呢?可以通过annotation进行配置,然后去实现这样的功能,这样在代码上也是比较简单的。



2、定义重试的注解



3、在request中定义变量



4、在builder中创建



5、对变量进行赋值并将变量返回



6、对注解进行处理






二、异步请求网络框架

1、定义变量初始化并赋值







2、httpclient功能的主要作用主要做一个网络层框架的抽象,它的基本作用主要是提供了一些网络层的基本操作,可以在这个地方增加一些异步请求的功能。异步请求的前提是线程应该在哪儿?所以需要新增一个成员变量ExecutorService mExecutor



3、在builder中定义


4、调用设置线程池的方法




5、定义重试



6、
发生异常时进行重试处理



代码:

package com.nice;

import com.nice.convert.Convert;
import com.nice.http.HttpDns;
import com.nice.http.HttpResponse;
import com.nice.http.Request;
import com.nice.http.Response;
import com.nice.http.client.okhttp.OkHttpClient;
import com.nice.http.client.origin.OriginHttpClient;
import com.nice.utils.TypeUtils;
import com.nice.utils.Utils;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.List;
import java.util.concurrent.ExecutorService;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

/**
 * 高度抽象的网络层接口
 * <p>主要提供升级超时、域名校验、证书认证、DNS等功能</p>
 *
 * @author nate
 * @since 2017/10/12.
 */

public class HttpClient implements Call {

    private static boolean OK_HTTP_REQUEST = Utils.isExist("okhttp3.OkHttpClient");

    private int mWriteTimeOut;
    private int mReaderTimeOut;
    private int mConnectTimeOut;
    private SSLSocketFactory mSSLSocketFactory;
    private HostnameVerifier mHostnameVerifier;
    private Call mRealHttpClient;
    private HttpDns mHttpDns;
    private Request mRequest;
    private Callback mCallback;
    private ExecutorService mExecutor;
    private List<Convert> mConverts;
    private int mRetryCount;

    public HttpClient(Builder builder) {
        mWriteTimeOut = builder.mWriteTimeOut;
        mReaderTimeOut = builder.mReaderTimeOut;
        mConnectTimeOut = builder.mConnectTimeOut;
        mSSLSocketFactory = builder.mSSLSocketFactory;
        mHostnameVerifier = builder.mHostnameVerifier;
        mHttpDns = builder.mHttpDns;
        mExecutor = builder.mExecutor;
        mConverts = builder.mConverts;
    }

    public HttpDns getHttpDns() {
        return mHttpDns;
    }

    public int getReaderTimeOut() {
        return mReaderTimeOut;
    }

    public int getConnectionTimeOut() {
        return mConnectTimeOut;
    }

    public int getWriteTimeOut() {
        return mWriteTimeOut;
    }

    public SSLSocketFactory getSSLSocketFactory() {
        return mSSLSocketFactory;
    }

    public HostnameVerifier getHostnameVerifier() {
        return mHostnameVerifier;
    }

    private boolean canRetry() {
        return mRetryCount < mRequest.getRetryCount();
    }

    private void retry() {
        if (mCallback != null && mRequest != null) {
            mRetryCount++;
            System.out.println("重试第" + mRetryCount + "次");
            enqueue(mRequest, mCallback);
        }
    }

    @Override
    public HttpResponse execute(Request request) throws IOException {
        if (OK_HTTP_REQUEST) {
            mRealHttpClient = new OkHttpClient(this);
        } else {
            mRealHttpClient = new OriginHttpClient(this);
        }
        return mRealHttpClient.execute(request);
    }

    /**
     * 异步处理网络请求
     *
     * @param request  网络请求对象
     * @param callback 回调方法
     */
    public void enqueue(final Request request, final Callback callback) {
        this.mRequest = request;
        this.mCallback = callback;
        mExecutor.execute(new Runnable() {
            @Override
            public void run() {
                invoke(request, callback.getClass());
            }
        });
    }

    /**
     * 将服务器数据转化成对应的类型
     *
     * @param response httpResponse
     * @param type     转换成的类型
     * @param <T>      返回值类型
     * @return 返回对应的值
     * @throws IOException
     */
    private <T> T convertResponse(HttpResponse response, Type type) throws IOException {
        Object result = response;
        for (int i = 0; i < mConverts.size(); i++) {
            Object data = mConverts.get(i).parse(result, type);
            if (data != null) {
                result = data;
            }
        }
        return (T) result;
    }

    private <T> Response parseResponse(T result, HttpResponse httpResponse) {
        return new Response(result, httpResponse);
    }

    public <T> T invoke(Request request, Class responseType) {
        Type type = TypeUtils.getType(responseType);
        HttpResponse httpResponse;
        final T result;
        try {
            httpResponse = execute(request);
            result = convertResponse(httpResponse, type);
        } catch (Throwable e) {
            e.printStackTrace();
            onFailure(e);
            if (canRetry()) {
                retry();
                return null;
            }
            return null;
        }
        Response response = parseResponse(result, httpResponse);
        onSuccess(response);
        return result;

    }

    private void onSuccess(Response response) {
        mCallback.onSuccess(response);
    }

    private void onFailure(Throwable error) {
        mCallback.onFailure(error);
    }


    public static class Builder {
        public static HostnameVerifier DEFAULT_HOST_NAME_VERIFIER = new DefaultHostnameVerifier();
        public static SSLSocketFactory DEFAULT_SSL_SOCKET_FACTORY = getDefaultSocketFactory();
        private int mWriteTimeOut;
        private int mReaderTimeOut;
        private int mConnectTimeOut;
        public SSLSocketFactory mSSLSocketFactory;
        private HostnameVerifier mHostnameVerifier;
        private HttpDns mHttpDns;
        private ExecutorService mExecutor;
        private List<Convert> mConverts;

        /**
         * 默认的域名校验实现
         */
        static class DefaultHostnameVerifier implements HostnameVerifier {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        }

        /**
         * 默认的证书管理
         */
        static class DefaultTrustManger implements X509TrustManager {

            @Override
            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {

            }


            @Override
            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {

            }

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[0];
            }
        }

        public static SSLSocketFactory getDefaultSocketFactory() {
            SSLContext context = null;
            try {
                context = SSLContext.getInstance("TLS");
                context.init(null, new TrustManager[]{new DefaultTrustManger()}, new SecureRandom());
            } catch (KeyManagementException e) {
                e.printStackTrace();
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
            return context.getSocketFactory();
        }

        public SSLSocketFactory getSocketFactory(InputStream inputStream) throws Exception {
            CertificateFactory factory = CertificateFactory.getInstance("x.509");
            X509Certificate certificate = (X509Certificate) factory.generateCertificate(inputStream);

            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(null, null);
            keyStore.setCertificateEntry("ca", certificate);

            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(keyStore);

            SSLContext context = SSLContext.getInstance("TLS");
            context.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());
            return context.getSocketFactory();
        }


        /**
         * 设置写入时间
         *
         * @param timeOut 设置的时间值
         * @return {@link Builder}
         */
        public Builder setWriteTimeOut(int timeOut) {
            this.mWriteTimeOut = timeOut;
            return this;
        }

        /**
         * 设置读取的时间
         *
         * @param timeOut 设置的时间值
         * @return {@link Builder}
         */
        public Builder setReaderTimeOut(int timeOut) {
            this.mReaderTimeOut = timeOut;
            return this;
        }

        /**
         * 设置网络连接时间
         *
         * @param timeOut 设置的时间值
         * @return {@link Builder}
         */
        public Builder setConnectionTimeOut(int timeOut) {
            this.mConnectTimeOut = timeOut;
            return this;
        }

        /**
         * 设置SSLSocket
         *
         * @param factory 具体的SSLSocketFactory实现
         * @return {@link Builder}
         */
        public Builder setSSLSocketFactory(SSLSocketFactory factory) {
            this.mSSLSocketFactory = factory;
            return this;
        }

        /**
         * 设置域名校验
         *
         * @param verifier 具体的域名校验实现
         * @return {@link Builder}
         */
        public Builder setHostnameVerifier(HostnameVerifier verifier) {
            this.mHostnameVerifier = verifier;
            return this;
        }

        /**
         * 设置HttpDns查询实现
         *
         * @param dns 具体的HttpDns查询实现
         * @return {@link Builder}
         */
        public Builder setHttpDns(HttpDns dns) {
            this.mHttpDns = dns;
            return this;
        }

        /**
         * 设置线程池
         *
         * @param service 线程池的实现
         * @return {@link Builder}
         */
        public Builder setExecutors(ExecutorService service) {
            this.mExecutor = service;
            return this;
        }

        /**
         * 设置转换的类型
         *
         * @param converts 转换类型的集合
         * @return {@link Builder}
         */
        public Builder setConverts(List<Convert> converts) {
            this.mConverts = converts;
            return this;
        }

        /**
         * 判断是否使用的了Http代理
         */
        private void proxy() {
            String host = System.getProperty("http.proxyHost");
            String port = System.getProperty("http.proxyPort");
            if (host != null && port != null) {
                mHttpDns = null;
            }
        }

        /**
         * 构建HttpClient对象
         *
         * @return {@link HttpClient}
         */
        public HttpClient builder() {
            proxy();
            return new HttpClient(this);
        }

    }
}




运行后如果出错,会进行重试操作




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值