okhttp 原始碼解析 - http 協議的實現 - 重定向

水牛發表於2017-03-08

http協議中的重定向

client:
向server傳送一個請求,要求獲取一個資源
server:
接收到這個請求後,發現請求的這個資源實際存放在另一個位置
於是server在返回的response header的Location欄位中寫入那個請求資源的正確的URL,並設定reponse的狀態碼為30x
client:
接收到這個response後,發現狀態碼為重定向的狀態嗎,就會去解析到新的URL,根據新的URL重新發起請求

狀態碼

重定向最常用為301,也有303,
臨時重定向用302,307

okhttp 原始碼解析 - http 協議的實現 - 重定向
Paste_Image.png

與請求轉發的對比

請求轉發
伺服器在處理request的過程中將request先後委託多個servlet或jsp接替進行處理的過程,request和reponse始終在期間傳遞

  • 重定向時,客戶端發起兩次請求,而請求轉發時,客戶端只發起一次請求
  • 重定向後,瀏覽器位址列url變成第二個url,而請求轉發沒有變(請求轉發對於客戶端是透明的)
  • 流程

    重定向:
    使用者請求-----》伺服器入口-------》元件------>伺服器出口-------》使用者----(重定向)---》新的請求
    請求轉發
    使用者請求-----》伺服器入口-------》元件1---(轉發)----》元件2------->伺服器出口-------》使用者

服務端實現

  • 重定向
    response.sendRedirect()
  • 請求轉發
    在Servlet裡,實現dispatch是通過RequestDispatchers來實現的,這個類有兩個方法:forward,include
    JSP裡實現dispatch的標籤也有兩個:

okhttp中的實現

邏輯

  • 讀取到響應狀態碼為30x時,拿到重定向的url,用這個url置換掉request中的原url
  • 對request的一些header,body分情況進行處理
  • 重新執行這個request,發出請求

程式碼實現

RetryAndFollowUpInterceptor的intercept方法中構建了while (true)迴圈,迴圈內部:

###1. 根據response重建request:Request followUp = followUpRequest(response)

int responseCode = userResponse.code();複製程式碼

然後switch (responseCode)進行判斷:

okhttp 原始碼解析 - http 協議的實現 - 重定向
Paste_Image.png

okhttp 原始碼解析 - http 協議的實現 - 重定向
Paste_Image.png

2.重新執行這個request:

將前一步得到的followUp 賦值給request,重新進入迴圈,

@Override public Response intercept(Chain chain) throws IOException {
    Request request = chain.request();

  ...
    while (true) {
      if (canceled) {
        streamAllocation.release();
        throw new IOException("Canceled");
      }

      Response response = null;
      boolean releaseConnection = true;
      try {
        response = ((RealInterceptorChain) chain).proceed(request, streamAllocation, null, null);//執行網路請求
        releaseConnection = false;
     ...

      Request followUp = followUpRequest(response);//拿到重定向的request

   if (followUp == null) {
        if (!forWebSocket) {
          streamAllocation.release();
        }
        return response;//如果不是重定向,就返回response
      }

      ...
    if (++followUpCount > MAX_FOLLOW_UPS) {//有最大次數限制20次
        streamAllocation.release();
        throw new ProtocolException("Too many follow-up requests: " + followUpCount);
      }

      request = followUp;//把重定向的請求賦值給request,以便再次進入迴圈執行
      priorResponse = response;
    }
  }複製程式碼

okhttp的相關配置

重定向功能預設是開啟的,可以選擇關閉,然後去實現自己的重定向功能:

new OkHttpClient().newBuilder()
                              .followRedirects(false)  //禁制OkHttp的重定向操作,我們自己處理重定向
                              .followSslRedirects(false)//https的重定向也自己處理複製程式碼

相關文章