gaolei1201
Allen/Gao
采纳率60%
2018-04-05 04:03 阅读 1.1k

请问各位大神Okhttp底层是如何实现拦截的?如何实现AOP的?研究了好久也看不出来,谢谢指教谢谢

80

图片说明
图片说明

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享

5条回答 默认 最新

  • 已采纳
    zull_kos_mos KosmoSakura 2018-04-08 03:08

    底层没研究过,我一般是这么使用的拦截器,你参考下:

    1.创建对象

      mOkHttpClient.newBuilder()
                        .cache(cache)//缓存路径
                        .cookieJar(CookiesManager.getInstance())
                        .retryOnConnectionFailure(true)
                        .connectTimeout(15, TimeUnit.SECONDS)
                        .readTimeout(300, TimeUnit.SECONDS)
                        .writeTimeout(300, TimeUnit.SECONDS)
                        .addNetworkInterceptor(cacheIntercepter)//网络拦截器
                        .build();
    

    2.拦截器

     //网络拦截器:设置缓存策略
        private Interceptor cacheIntercepter = new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                Request request = chain.request();
    
                //无网的时候强制使用缓存
                if (!NetworkUtil.isConnected()) {
                    ToastUtil.showShortMessage("网络不可用,开始加载本地缓存");
                    request = request.newBuilder()
                            .cacheControl(CacheControl.FORCE_CACHE)
                            .build();
                }
    
                Response response = chain.proceed(request);
    
                //有网的时候读接口上的@Headers里的配置,你可以在这里进行统一的设置
                if (NetworkUtil.isConnected()) {
                    String cacheControl = request.cacheControl().toString();
                    return response.newBuilder()
    //                    .addHeader("TerminalCode", "android_app")
    //                    .addHeader("TerminalVersion", "v" + FrameWorkSetting.clientVersion)
    //                    .addHeader("TerminalSim", FrameWorkSetting.phoneMODEL)
                            .header("Cache-Control", cacheControl)
                            .removeHeader("Pragma")
                            .build();
                } else {
                    int maxStale = 60 * 60 * 24 * 28; // tolerate 4-weeks stale
                    return response.newBuilder()
    //                    .addHeader("TerminalCode", "android_app")
    //                    .addHeader("TerminalVersion", "v" + FrameWorkSetting.clientVersion)
    //                    .addHeader("TerminalSim", FrameWorkSetting.phoneMODEL)
                            .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
                            .removeHeader("Pragma")
                            .build();
                }
            }
    
        };
    
    点赞 评论 复制链接分享
  • huageng1 huageng1 2018-04-08 08:41

    使用OKHTTP发起一个GET请求:
    OkHttpClient client = new OkHttpClient();
    String run(String url) throws IOException {
    Request request = new Request.Builder() .url(url) .build();
    Response response = client.newCall(request).execute();
    return response.body().string(); 、
    }

    一直往下跟踪:

    @Override public Call newCall(Request request) {
    return new RealCall(this, request);
    }

    返回一个RealCall,
    调用RealCall的execute()方法:
    @Override public Response execute() throws IOException {
    synchronized (this) {
    if (executed) throw new IllegalStateException("Already Executed");
    executed = true;
    }
    try {
    client.dispatcher().executed(this);
    Response result = getResponseWithInterceptorChain(false);
    if (result == null) throw new IOException("Canceled");
    return result;
    } finally {
    client.dispatcher().finished(this);
    }
    }

    调用getResponseWithInterceptorChain():
    private Response getResponseWithInterceptorChain(boolean forWebSocket) throws IOException {
    Interceptor.Chain chain = new ApplicationInterceptorChain(0, originalRequest, forWebSocket);
    return chain.proceed(originalRequest);
    }

    这时候会创建一个拦截器链:
    Interceptor.Chain chain = new ApplicationInterceptorChain(0, originalRequest, forWebSocket);
    看看ApplicationInterceptorChain的构造函数:
    ApplicationInterceptorChain(int index, Request request, boolean forWebSocket) {
    this.index = index;
    this.request = request;
    this.forWebSocket = forWebSocket;
    }
    其中第一个参数是一个index,此处请注意,最初我们传入的index的值是0,

    继续看chain.proceed(originalRequest);
    此时会调用到ApplicationInterceptorChain中:

    @Override public Response proceed(Request request) throws IOException {
    // If there's another interceptor in the chain, call that.
    if (index < client.interceptors().size()) {
    Interceptor.Chain chain = new ApplicationInterceptorChain(index + 1, request, forWebSocket);
    Interceptor interceptor = client.interceptors().get(index);
    Response interceptedResponse = interceptor.intercept(chain);

        if (interceptedResponse == null) {
          throw new NullPointerException("application interceptor " + interceptor
              + " returned null");
        }
    
        return interceptedResponse;
      }
    
      // No more interceptors. Do HTTP.
      return getResponse(request, forWebSocket);
    

    }

    会根据index从0开始先取出拦截器并依次执行,但是我们需要注意的是,在重新构造chain的时候会把index的值加1,在调用拦截器的拦截方法的时候会将拦截器链作为参数传入,单此时index的值已经修改了,

    我们再看拦截器的方法:
    @Override public Response intercept(Chain chain) throws IOException {
    Level level = this.level;

    Request request = chain.request();
    if (level == Level.NONE) {
      return chain.proceed(request);
    

    }
    在该方法中又会调用chain.proceed(request)方法;
    相当于在返回最终结果前,会先依次调用我们注册的拦截器的方法,最后才会返回最终结果,从而实现了AOP类似的功能

    如此来看,每个拦截器都可以看成是一个切面

    点赞 1 评论 复制链接分享
  • qq_41209725 A皮卡 2018-04-05 05:56

    检查一下 return 的格式,顺便看一下是否存在逻辑错误。代码检查比较麻烦,没办法

    点赞 评论 复制链接分享
  • gaolei1201 Allen/Gao 2018-04-08 02:17

    这么有名的框架 还会存在逻辑错误?

    点赞 评论 复制链接分享
  • huageng1 huageng1 2018-04-08 08:40

    附一张图
    图片说明

    点赞 评论 复制链接分享

相关推荐