All Projects → CodeLiuPu → UHttp

CodeLiuPu / UHttp

Licence: other
手写自己的OkHttp (用法流程跟OkHttp一致 )

Programming Languages

java
68154 projects - #9 most used programming language

Projects that are alternatives of or similar to UHttp

SunnyBeach
阳光沙滩APP
Stars: ✭ 60 (+328.57%)
Mutual labels:  okhttp
simpleRPC
Simple RPC implementation for Arduino.
Stars: ✭ 28 (+100%)
Mutual labels:  simple
simple-image-classifier
Simple image classifier microservice using tensorflow and sanic
Stars: ✭ 22 (+57.14%)
Mutual labels:  simple
simple-debug.css
Debug your layouts with one line of CSS
Stars: ✭ 32 (+128.57%)
Mutual labels:  simple
Simple-YouTube-Downloader
YouTube download client with focus on simplicity
Stars: ✭ 31 (+121.43%)
Mutual labels:  simple
SSTMCSPGAAS
Stupidly Simple Tiny Minimal Coming Soon Page Generator As A Service
Stars: ✭ 23 (+64.29%)
Mutual labels:  simple
OkHttp3Utils
OkHttp3.0网络工具类
Stars: ✭ 34 (+142.86%)
Mutual labels:  okhttp
sol
Lightweight MQTT broker, written from scratch. IO is handled by a super simple event loop based upon the most common IO multiplexing implementations.
Stars: ✭ 72 (+414.29%)
Mutual labels:  simple
Ugly-Distributed-Crawler
基于Redis实现的简单到爆的分布式爬虫
Stars: ✭ 45 (+221.43%)
Mutual labels:  simple
flip-jump
The simplest programming language - Flip a bit, then Jump
Stars: ✭ 18 (+28.57%)
Mutual labels:  simple
django-menu-generator
A straightforward menu generator for Django
Stars: ✭ 24 (+71.43%)
Mutual labels:  simple
okhttp-awssigner
An OkHttp interceptor for signing requests with AWSv4 signatures
Stars: ✭ 14 (+0%)
Mutual labels:  okhttp
TMDB-App
Demo app using TMDB api
Stars: ✭ 13 (-7.14%)
Mutual labels:  okhttp
perf
PERF is an Exhaustive Repeat Finder
Stars: ✭ 26 (+85.71%)
Mutual labels:  simple
pasthis
Simple stupid pastebin
Stars: ✭ 36 (+157.14%)
Mutual labels:  simple
elcalc
➗ Cross-Platform calculator built with Electron!
Stars: ✭ 88 (+528.57%)
Mutual labels:  simple
contentfully
A simple but performant REST client for Contentful.
Stars: ✭ 13 (-7.14%)
Mutual labels:  simple
apps-script-db
A key-value database by Google Apps Script
Stars: ✭ 20 (+42.86%)
Mutual labels:  simple
printrboardmodernmarlin
Printrboard and Modern Marlin
Stars: ✭ 55 (+292.86%)
Mutual labels:  simple
Chat-Server
Simple chatroom in C
Stars: ✭ 74 (+428.57%)
Mutual labels:  simple

UpdateHttp

1 前言

项目一直用的OkHttp,对其流程也一直是一知半解,最近复习了下网络知识和设计模式,又查阅了大佬的博客,把OkHttp的逻辑基本走通了,就仿着 OkHttp 写了一个框架,思路以及用法跟OkHttp一样,用于熟悉OkHttp的细节,加深下记忆

2 OkHttp请求流程

2.1 请求流程如下图

okhttp_full_process.png

手写的UpdateHttp流程与OkHttp 一致 并精简了一部分,可以先看精简后的源码来熟悉OkHttp的源码

3 使用方式

3.1 get方式

Request request = new Request.Builder()
           .setHttpUrl("http://gank.io/api/today")
           .get()
           .build();

   HttpClient httpClient = new HttpClient.Builder()
           .setRetryTimes(3)
           .build();
   Call call = httpClient.newCall(request);
   call.enqueue(new CallBack() {
       @Override
       public void onFailure(Call call, Throwable throwable) {

       }

       @Override
       public void onResponse(Call call, Response response) {
           L.i("get body = " + response.getBody());
       }
   });

3.2 post方式

RequestBody requestBody = new RequestBody()
           .add("username", "hh123")
           .add("password", "123456");
   Request request = new Request.Builder()
           .setHttpUrl("http://www.wanandroid.com/user/login")
           .post(requestBody)
           .build();

   HttpClient httpClient = new HttpClient.Builder()
           .setRetryTimes(3)
           .build();
   Call call = httpClient.newCall(request);
   call.enqueue(new CallBack() {
       @Override
       public void onFailure(Call call, Throwable throwable) {

       }

       @Override
       public void onResponse(Call call, Response response) {
           L.i("post body = " + response.getBody());
       }
   });

4 具体实现(核心部分)

###包结构图

QQ20190130-101123.png

Request

public class Request {

    public static final String METHOD_GET = "GET";
    public static final String METHOD_POST = "POST";

    private Map<String, String> headers;
    private String method;
    private HttpUrl httpUrl;
    private RequestBody requestBody;

    public Map<String, String> getHeaders() {
        return headers;
    }

    public HttpUrl getHttpUrl() {
        return httpUrl;
    }

    public RequestBody getRequestBody() {
        return requestBody;
    }

    public String getMethod() {
        return method;
    }

    public Request(Builder builder) {
        this.headers = builder.headers;
        this.method = builder.method;
        this.httpUrl = builder.httpUrl;
        this.requestBody = builder.requestBody;
    }

    public static final class Builder {
        private Map<String, String> headers = new HashMap<>();
        private String method = METHOD_GET;
        private HttpUrl httpUrl;
        private RequestBody requestBody;

        public Builder addHeader(String key, String value) {
            headers.put(key, value);
            return this;
        }

        public Builder removeHeader(String key) {
            headers.remove(key);
            return this;
        }

        public Builder post(RequestBody requestBody) {
            method = Request.METHOD_POST;
            this.requestBody = requestBody;
            return this;
        }

        public Builder setHttpUrl(String url) {
            try {
                this.httpUrl = new HttpUrl(url);
                return this;
            } catch (MalformedURLException e) {
                throw new IllegalStateException("http url format error!", e);
            }
        }


        public Builder get() {
            method = Request.METHOD_GET;
            return this;
        }

        public Request build() {
            if (httpUrl == null) {
                throw new IllegalStateException("url is null!");
            }
            return new Request(this);
        }
    }
}
使用了建造者模式

HttpClient

public class HttpClient {

    private Dispatcher dispatcher;

    private List<Interceptor> interceptors;

    private int retryTimes;

    private ConnectionPool connectionPool;

    public int getRetryTimes() {
        return retryTimes;
    }

    public Dispatcher getDispatcher() {
        return dispatcher;
    }

    public List<Interceptor> getInterceptors() {
        return interceptors;
    }

    public ConnectionPool getConnectionPool() {
        return connectionPool;
    }

    public HttpClient(Builder builder) {
        this.dispatcher = builder.dispatcher;
        this.interceptors = builder.interceptors;
        this.connectionPool = builder.connectionPool;
        this.retryTimes = builder.retryTimes;
    }

    /**
     * 生成一个网络请求Call实例
     *
     * @param request
     * @return
     */
    public Call newCall(Request request) {
        return new Call(this, request);
    }

    public static final class Builder {

        private Dispatcher dispatcher = new Dispatcher();
        private List<Interceptor> interceptors = new ArrayList<>();
        private int retryTimes = 4;
        private ConnectionPool connectionPool = new ConnectionPool();

        public Builder addInterceptor(Interceptor interceptor) {
            interceptors.add(interceptor);
            return this;
        }

        public Builder setRetryTimes(int retryTimes) {
            this.retryTimes = retryTimes;
            return this;
        }

        public Builder setConnectionPool(ConnectionPool connectionPool) {
            this.connectionPool = connectionPool;
            return this;
        }

        public Builder setDispatcher(Dispatcher dispatcher) {
            this.dispatcher = dispatcher;
            return this;
        }

        public HttpClient build() {
            return new HttpClient(this);
        }
    }
}
使用了建造者模式
内部维护了一个 Interceptor 列表,用于添加自定义的 Interceptor
维护了一个 Dispatcher 用于管理 请求

Call

public class Call {

    private HttpClient httpClient;
    private Request request;
    boolean executed;
    boolean canceled;

    public HttpClient getHttpClient() {
        return httpClient;
    }

    public Request getRequest() {
        return request;
    }

    public boolean isCanceled() {
        return canceled;
    }

    public Call(HttpClient httpClient, Request request) {
        this.httpClient = httpClient;
        this.request = request;
    }

    Response getResponseWithInterceptorChain() throws IOException {
        L.i("getResponseWithInterceptorChain");

        List<Interceptor> interceptors = new ArrayList<>();
        interceptors.addAll(httpClient.getInterceptors());
        interceptors.add(new RetryIntercepor());
        interceptors.add(new BridgeInterceptor());
        interceptors.add(new CacheInterceptor());
        interceptors.add(new ConnectionInterceptor());
        interceptors.add(new CallServerInterceptor());

        InterceptorChain interceptorChain = new InterceptorChain(interceptors, 0, this, null);
        Response response = interceptorChain.proceed();
        return response;
    }

    public Call enqueue(CallBack callBack) {
        synchronized (this) {
            if (executed) {
                throw new IllegalStateException("This Call Already Executed!");
            }
            executed = true;
        }

        httpClient.getDispatcher().enqueue(new AsyncCall(callBack));
        return this;
    }

    final class AsyncCall implements Runnable {

        private CallBack callBack;

        public AsyncCall(CallBack callBack) {
            this.callBack = callBack;
        }

        @Override
        public void run() {
            /**
             * 是否返回
             */
            boolean signalledCallback = false;
            try {
                Response response = getResponseWithInterceptorChain();
                if (canceled) {
                    signalledCallback = true;
                    callBack.onFailure(Call.this, new IOException("this task is canceled"));
                } else {
                    signalledCallback = true;
                    callBack.onResponse(Call.this, response);
                }
            } catch (IOException e) {
                if (!signalledCallback) {
                    callBack.onFailure(Call.this, e);
                }
            } finally {
                /**
                 *  将任务从调度器中移除
                 */
                httpClient.getDispatcher().finished(this);
            }

        }

        public String getHost() {
            return request.getHttpUrl().getHost();
        }
    }
}
在Call 内部 来添加拦截器链
在拦截器链中进行了真正的网络请求部分

5 总结:

引用别人的话 "我们不重复造轮子不表示我们不需要知道轮子该怎么造及如何更好的造"
不去重复造轮子,但我感觉还是去亲手实现下,才会对其中的细节部分了解的更加的清晰,通过仿造OkHttp,可以学到其中的思想,以及精美的设计模式用法,这样就够了

简书地址

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].