OkHttp文檔翻譯篇——(7)

上一篇:6(HTTPS)

7,Events(原文網頁

通過Events你可以監控你應用中的HTTP請求整個過程,通過它我們可以監控:

  • (1)你的應用中HTTP請求的大小與頻率,我們可以通過它來獲取像特別大的請求或者請求過於頻繁的情況
  • (2)這些調用在基礎網絡上的性能。如果網絡的性能不夠,您需要改進網絡或減少網絡的使用。

7.1  EventListener(時間監聽)

在EventListener的子類中重寫方法你關注的方法。在沒有重定向或重試的成功HTTP調用中,事件的執行流程如下圖所示。

下面是一個簡單的事件監聽示例,我們在每個事件執行時打印對應的時間戳

class PrintingEventListener extends EventListener {
  private long callStartNanos;

  private void printEvent(String name) {
    long nowNanos = System.nanoTime();
    if (name.equals("callStart")) {
      callStartNanos = nowNanos;
    }
    long elapsedNanos = nowNanos - callStartNanos;
    System.out.printf("%.3f %s%n", elapsedNanos / 1000000000d, name);
  }

  @Override public void callStart(Call call) {
    printEvent("callStart");
  }

  @Override public void callEnd(Call call) {
    printEvent("callEnd");
  }

  @Override public void dnsStart(Call call, String domainName) {
    printEvent("dnsStart");
  }

  @Override public void dnsEnd(Call call, String domainName, List<InetAddress> inetAddressList) {
    printEvent("dnsEnd");
  }

  ...
}

我們執行兩次HTTP請求調用:

Request request = new Request.Builder()
    .url("https://publicobject.com/helloworld.txt")
    .build();

System.out.println("REQUEST 1 (new connection)");
try (Response response = client.newCall(request).execute()) {
  // Consume and discard the response body.
  response.body().source().readByteString();
}

System.out.println("REQUEST 2 (pooled connection)");
try (Response response = client.newCall(request).execute()) {
  // Consume and discard the response body.
  response.body().source().readByteString();
}

執行過程中打印的日誌如下:

REQUEST 1 (new connection)
0.000 callStart
0.010 dnsStart
0.017 dnsEnd
0.025 connectStart
0.117 secureConnectStart
0.586 secureConnectEnd
0.586 connectEnd
0.587 connectionAcquired
0.588 requestHeadersStart
0.590 requestHeadersEnd
0.591 responseHeadersStart
0.675 responseHeadersEnd
0.676 responseBodyStart
0.679 responseBodyEnd
0.679 connectionReleased
0.680 callEnd
REQUEST 2 (pooled connection)
0.000 callStart
0.001 connectionAcquired
0.001 requestHeadersStart
0.001 requestHeadersEnd
0.002 responseHeadersStart
0.082 responseHeadersEnd
0.082 responseBodyStart
0.082 responseBodyEnd
0.083 connectionReleased
0.083 callEnd

注意觀察爲什麼第二次的HTTP請求調用的連接過程的事件回調都沒有走,因爲它重用了第一個請求中的連接,這樣可以顯著提高性能。

7.2  EventListener.Factory(事件監聽工廠)

在前面的示例中,我們使用了一個字段callstartnoss來跟蹤每個事件的運行時間。這很方便,但如果同時執行多個調用,它將不起作用。要適應這種情況,請使用工廠爲每個調用創建一個新的EventListener實例。這允許每個偵聽器與特定調用的狀態對應起來。

此示例工廠爲每個調用創建一個唯一的ID,並使用該ID區分每次調用的日誌消息。

class PrintingEventListener extends EventListener {
  public static final Factory FACTORY = new Factory() {
    final AtomicLong nextCallId = new AtomicLong(1L);

    @Override public EventListener create(Call call) {
      long callId = nextCallId.getAndIncrement();
      System.out.printf("%04d %s%n", callId, call.request().url());
      return new PrintingEventListener(callId, System.nanoTime());
    }
  };

  final long callId;
  final long callStartNanos;

  public PrintingEventListener(long callId, long callStartNanos) {
    this.callId = callId;
    this.callStartNanos = callStartNanos;
  }

  private void printEvent(String name) {
    long elapsedNanos = System.nanoTime() - callStartNanos;
    System.out.printf("%04d %.3f %s%n", callId, elapsedNanos / 1000000000d, name);
  }

  @Override public void callStart(Call call) {
    printEvent("callStart");
  }

  @Override public void callEnd(Call call) {
    printEvent("callEnd");
  }

  ...
}

我們可以通過上面的監聽器來對比下面兩個同時發出的HTTP請求執行結果:

Request washingtonPostRequest = new Request.Builder()
    .url("https://www.washingtonpost.com/")
    .build();
client.newCall(washingtonPostRequest).enqueue(new Callback() {
  ...
});

Request newYorkTimesRequest = new Request.Builder()
    .url("https://www.nytimes.com/")
    .build();
client.newCall(newYorkTimesRequest).enqueue(new Callback() {
  ...
});

在家庭WiFi下,執行的結果顯示紐約時報網站(0002)的響應速度要比華盛頓郵報網站(0001)要稍快一些:

0001 https://www.washingtonpost.com/
0001 0.000 callStart
0002 https://www.nytimes.com/
0002 0.000 callStart
0002 0.010 dnsStart
0001 0.013 dnsStart
0001 0.022 dnsEnd
0002 0.019 dnsEnd
0001 0.028 connectStart
0002 0.025 connectStart
0002 0.072 secureConnectStart
0001 0.075 secureConnectStart
0001 0.386 secureConnectEnd
0002 0.390 secureConnectEnd
0002 0.400 connectEnd
0001 0.403 connectEnd
0002 0.401 connectionAcquired
0001 0.404 connectionAcquired
0001 0.406 requestHeadersStart
0002 0.403 requestHeadersStart
0001 0.414 requestHeadersEnd
0002 0.411 requestHeadersEnd
0002 0.412 responseHeadersStart
0001 0.415 responseHeadersStart
0002 0.474 responseHeadersEnd
0002 0.475 responseBodyStart
0001 0.554 responseHeadersEnd
0001 0.555 responseBodyStart
0002 0.554 responseBodyEnd
0002 0.554 connectionReleased
0002 0.554 callEnd
0001 0.624 responseBodyEnd
0001 0.624 connectionReleased
0001 0.624 callEnd

通過實踐監聽工廠,我們還可以設置監聽請求調用的頻率,比如下面的示例就展示了我們只監聽全部請求的10%

class MetricsEventListener extends EventListener {
  private static final Factory FACTORY = new Factory() {
    @Override public EventListener create(Call call) {
      if (Math.random() < 0.10) {
        return new MetricsEventListener(call);
      } else {
        return EventListener.NONE;
      }
    }
  };

  ...
}

7.3  Events with Failures(失敗事件監聽)

當連接或者請求調用失敗時,對應的失敗方法會調用。比如,建立連接失敗會調用connectfailed()方法;當HTTP調用一直失敗時調用callfailed()方法。當上面情況發生時,開始事件可能沒有相應的結束事件。

 

7.4  Events with Retries and Follow-Ups(重連事件監聽與後續事件監聽)

OKHTTP可以從某些連接故障中自動恢復。在這種情況下,connectFailed()事件並不是終結事件,後面也不會直接調用callFailed()。在嘗試重連時,事件偵聽器可能會接收多個相同類型(connectFailed())的事件。

單個HTTP調用可能需要發出後續請求來處理身份驗證、重定向和HTTP層超時等情況。在這些情況下,多個連接建立、請求和響應可能會執行。這也是單個調用可能觸發同一類型事件多次回調的另一個原因

 

7.5  Availability(使用說明)

在OkHttp3.11的發佈API版本中可用。後續版本中可能定義一些新的回調事件。如果你想處理某事件,一定要重寫對應的事件。

 

注:如果對您有幫助,歡迎掃碼關注

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章