關于Interceptor

什么是Interceptor:

Interceptor翻譯過來就是攔截器竟趾,它是OkHttp網絡請求中抓取請求和響應必須的一個全能王漾峡。

你如果用過okhttp定欧,一定對HttpLoggingInterceptor不陌生信殊,這個是squareup公司寫的一個樣板挽绩,其實它呢也就是告訴你了任何你想拿到的數據⊙咚看源碼么赵刑,go。场刑。般此。

public final class HttpLoggingInterceptor implements Interceptor {
  private static final Charset UTF8 = Charset.forName("UTF-8");
//設置攔截級別,枚舉4種
  public enum Level {
    NONE,
    BASIC,
    HEADERS,
    BODY
  }
牵现。铐懊。。瞎疼。科乎。。贼急。茅茂。捏萍。。
空闲。令杈。。碴倾。逗噩。。影斑。。机打。矫户。
。残邀。皆辽。。芥挣。驱闷。。空免。空另。。
  @Override public Response intercept(Chain chain) throws IOException {
    Level level = this.level;
    Request request = chain.request();
    if (level == Level.NONE) {
      //不攔截蹋砚,直接返回
      return chain.proceed(request);
    }
    boolean logBody = level == Level.BODY;
    boolean logHeaders = logBody || level == Level.HEADERS;
    RequestBody requestBody = request.body();
    boolean hasRequestBody = requestBody != null;
    //建立連接
    Connection connection = chain.connection();
    //拿到連接協議扼菠,如果連接不存在就直接用http_1_1協議
    Protocol protocol = connection != null ? connection.protocol() : Protocol.HTTP_1_1;
    String requestStartMessage = "--> " + request.method() + ' ' + request.url() + ' ' + protocol;
    //如果設置的級別是base,就打印頭部分
    if (!logHeaders && hasRequestBody) {
      requestStartMessage += " (" + requestBody.contentLength() + "-byte body)";
    }
    logger.log(requestStartMessage);
    //如果設置的級別是頭坝咐,就打印頭部分
    if (logHeaders) {
      //如果有請求體循榆,就將請求體的長度和類型打印
      if (hasRequestBody) {
        //請求頭的值,存在就攔截
        if (requestBody.contentType() != null) {
          logger.log("Content-Type: " + requestBody.contentType());
        }
        //-1代表請求數據長度0
        if (requestBody.contentLength() != -1) {
          logger.log("Content-Length: " + requestBody.contentLength());
        }
      }
      //請求頭部分墨坚,遍歷打印
      Headers headers = request.headers();
      for (int i = 0, count = headers.size(); i < count; i++) {
        String name = headers.name(i);
        // 這里因為上面已經打印了秧饮,所以就過濾一下
        if (!"Content-Type".equalsIgnoreCase(name) && !"Content-Length".equalsIgnoreCase(name)) {
          logger.log(name + ": " + headers.value(i));
        }
      }
      //沒有請求體,或者等級沒有設置為打印請求體泽篮,結束打印
      if (!logBody || !hasRequestBody) {
        logger.log("--> END " + request.method())盗尸;
      } else if (bodyEncoded(request.headers())) {
        //有請求體或者log等級設置為body,打印請求頭中設置的編碼
        logger.log("--> END " + request.method() + " (encoded body omitted)");
      } else {
        //將請求體數據給寫進緩存流
        Buffer buffer = new Buffer();
        requestBody.writeTo(buffer);
        //設置編碼為utf-8
        Charset charset = UTF8;
        MediaType contentType = requestBody.contentType();
        if (contentType != null) {
          charset = contentType.charset(UTF8);
        }

        logger.log("");
      //判斷是否是人類可讀的字符帽撑,是就打印
        if (isPlaintext(buffer)) {
          logger.log(buffer.readString(charset));
          logger.log("--> END " + request.method()
              + " (" + requestBody.contentLength() + "-byte body)");
        } else {
          //人類不懂振劳,就用二進制讀出來
          logger.log("--> END " + request.method() + " (binary "
              + requestBody.contentLength() + "-byte body omitted)");
        }
      }
    }

    long startNs = System.nanoTime();
    Response response;
    try {
      //請求開始
      response = chain.proceed(request);
    } catch (Exception e) {
      //請求異常
      logger.log("<-- HTTP FAILED: " + e);
      throw e;
    }
    //請求花費時間
    long tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs);
    //響應體了
    ResponseBody responseBody = response.body();
    long contentLength = responseBody.contentLength();
    String bodySize = contentLength != -1 ? contentLength + "-byte" : "unknown-length";
    //打印長度和響應碼,響應信息油狂,響應體對應請求體(這里要考慮重定向url)历恐,請求耗費時間寸癌,響應體長度
    logger.log("<-- " + response.code() + ' ' + response.message() + ' '
        + response.request().url() + " (" + tookMs + "ms" + (!logHeaders ? ", "
        + bodySize + " body" : "") + ')');
    //打印響應頭
    if (logHeaders) {
      Headers headers = response.headers();
      for (int i = 0, count = headers.size(); i < count; i++) {
        logger.log(headers.name(i) + ": " + headers.value(i));
      }
       //響應體不存在,等級不為body
      if (!logBody || !HttpHeaders.hasBody(response)) {
        logger.log("<-- END HTTP");
      } else if (bodyEncoded(response.headers())) {
        //響應體編碼不對稱
        logger.log("<-- END HTTP (encoded body omitted)");
      } else {
        //source弱贼,響應體來了
        BufferedSource source = responseBody.source();
        //設置最大緩存大小蒸苇,當然是緩存整個body嘍,全吃
        source.request(Long.MAX_VALUE); 
        Buffer buffer = source.buffer()吮旅;
        Charset charset = UTF8;
        //拿到media類型對應的字符集
        MediaType contentType = responseBody.contentType();
        if (contentType != null) {
          try {
            charset = contentType.charset(UTF8);
          } catch (UnsupportedCharsetException e) {
            logger.log("");
            logger.log("Couldn't decode the response body; charset is likely malformed.");
            logger.log("<-- END HTTP");

            return response;
          }
        }
        //如果不是人類能看懂的溪烤,就不打印string形式的嘍
        if (!isPlaintext(buffer)) {
          logger.log("");
          logger.log("<-- END HTTP (binary " + buffer.size() + "-byte body omitted)");
          return response;
        }
        //是人類懂的,就開始讀string嘍
        if (contentLength != 0) {
          logger.log("");
          logger.log(buffer.clone().readString(charset));
        }
        //最后打印body的長度
        logger.log("<-- END HTTP (" + buffer.size() + "-byte body)");
      }
    }

    return response;
  }

  /**
   *判斷緩存流的數據是否是人類能讀懂的庇勃,哈哈檬嘀,也就是abc123唄
   */
  static boolean isPlaintext(Buffer buffer) {
     //先判斷是不是123abc能看懂的
    try {
      Buffer prefix = new Buffer();
      long byteCount = buffer.size() < 64 ? buffer.size() : 64;
      buffer.copyTo(prefix, 0, byteCount);
      for (int i = 0; i < 16; i++) {
        if (prefix.exhausted()) {
          break;
        }
        //再判斷是不是iso8859-1之類的,當然不是能懂的啊
        int codePoint = prefix.readUtf8CodePoint();
        if (Character.isISOControl(codePoint) && !Character.isWhitespace(codePoint)) {
          return false;
        }
      }
      return true;
    } catch (EOFException e) {
      return false; // Truncated UTF-8 sequence.
    }
  }
  //返回頭中的編碼是否存在并且不是identity责嚷,一般都是gzip,deflate,compress之中一個
  private boolean bodyEncoded(Headers headers) {
    String contentEncoding = headers.get("Content-Encoding");
    return contentEncoding != null && !contentEncoding.equalsIgnoreCase("identity");
  }
}

好了終于擼了一遍源碼鸳兽,相信還有很多朋友沒有看懂,解釋這些源碼干嘛啊罕拂,另外推薦一篇文章揍异,大家踴躍去看吧(感謝ychongjie的攔截器細致分析):
鏈接直通車

沒有太多時間更新和維護,有什么不妥的請指出爆班,匆忙的成果衷掷,畢竟公司團隊項目你不做其他人多做,多少有點坑隊友柿菩,dota骨灰級玩家怎么能做出這種事情呢戚嗅,不定期更新中。枢舶。渡处。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市祟辟,隨后出現的幾起案子医瘫,更是在濱河造成了極大的恐慌,老刑警劉巖旧困,帶你破解...
    沈念sama閱讀 212,080評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件醇份,死亡現場離奇詭異,居然都是意外死亡吼具,警方通過查閱死者的電腦和手機僚纷,發(fā)現死者居然都...
    沈念sama閱讀 90,422評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拗盒,“玉大人怖竭,你說我怎么就攤上這事《赣” “怎么了痊臭?”我有些...
    開封第一講書人閱讀 157,630評論 0 348
  • 文/不壞的土叔 我叫張陵哮肚,是天一觀的道長。 經常有香客問我广匙,道長允趟,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,554評論 1 284
  • 正文 為了忘掉前任鸦致,我火速辦了婚禮潮剪,結果婚禮上,老公的妹妹穿的比我還像新娘分唾。我一直安慰自己抗碰,他們只是感情好,可當我...
    茶點故事閱讀 65,662評論 6 386
  • 文/花漫 我一把揭開白布绽乔。 她就那樣靜靜地躺著弧蝇,像睡著了一般。 火紅的嫁衣襯著肌膚如雪迄汛。 梳的紋絲不亂的頭發(fā)上捍壤,一...
    開封第一講書人閱讀 49,856評論 1 290
  • 那天骤视,我揣著相機與錄音鞍爱,去河邊找鬼。 笑死专酗,一個胖子當著我的面吹牛睹逃,可吹牛的內容都是我干的。 我是一名探鬼主播祷肯,決...
    沈念sama閱讀 39,014評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼沉填,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了佑笋?” 一聲冷哼從身側響起翼闹,我...
    開封第一講書人閱讀 37,752評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蒋纬,沒想到半個月后猎荠,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 44,212評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡蜀备,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,541評論 2 327
  • 正文 我和宋清朗相戀三年关摇,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片碾阁。...
    茶點故事閱讀 38,687評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡输虱,死狀恐怖,靈堂內的尸體忽然破棺而出脂凶,到底是詐尸還是另有隱情宪睹,我是刑警寧澤愁茁,帶...
    沈念sama閱讀 34,347評論 4 331
  • 正文 年R本政府宣布,位于F島的核電站横堡,受9級特大地震影響埋市,放射性物質發(fā)生泄漏。R本人自食惡果不足惜命贴,卻給世界環(huán)境...
    茶點故事閱讀 39,973評論 3 315
  • 文/蒙蒙 一道宅、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧胸蛛,春花似錦污茵、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,777評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至民珍,卻和暖如春襟士,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背嚷量。 一陣腳步聲響...
    開封第一講書人閱讀 32,006評論 1 266
  • 我被黑心中介騙來泰國打工陋桂, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蝶溶。 一個月前我還...
    沈念sama閱讀 46,406評論 2 360
  • 正文 我出身青樓嗜历,卻偏偏與公主長得像,于是被迫代替她去往敵國和親抖所。 傳聞我的和親對象是個殘疾皇子梨州,可洞房花燭夜當晚...
    茶點故事閱讀 43,576評論 2 349

推薦閱讀更多精彩內容