OkHttp 분석 시리즈-방향 변경 및 오류 재 시도

14300 단어 자바androidhttp
&emps;이것 은 OkHttp 시리즈 박문 의 첫 번 째 편 입 니 다.예전 에 초 고 를 써 서 OkHttp 의 전체적인 구 조 를 소개 한 적 이 있 지만 관련 된 지식 이 너무 많아 서 한 편 에서 분명하게 설명 할 수 없 을 것 같 습 니 다.그래서 그 후의 박문 은 특정한 분야 의 지식 에 만 관심 을 가지 고 짧 고 간결 하 게 글 을 얻 도록 하 겠 습 니 다. 오늘 은 주로 OkHttp 가 Http 요청 을 보 내 는 과정 에서 의 재 설정 과 오류 재 시도 에 대해 연 구 했 습 니 다.주로 관련 된 소스 파일 은 Call.java``HttpEngine.java 입 니 다. 우 리 는 오늘 CallResponse getResponse(Request request, boolean forWebSocket) throws IOException 함 수 를 연구 합 니 다.이것 은 Call.execute()Response 으로 호출 한 핵심 함수 입 니 다.주요 기능 은 HttpEngine 을 새로 만 들 고 Request 을 보 낸 다음 에 오류 재 시도 와 재 설정 문 제 를 처리 하 는 것 입 니 다.
헤더 설정
  // Copy body metadata to the appropriate request headers.
    RequestBody body = request.body();
    if (body != null) {
      Request.Builder requestBuilder = request.newBuilder();//       

      MediaType contentType = body.contentType();
      if (contentType != null) {
        requestBuilder.header("Content-Type", contentType.toString());
      }

      long contentLength = body.contentLength();
      if (contentLength != -1) {
        requestBuilder.header("Content-Length", Long.toString(contentLength));
        requestBuilder.removeHeader("Transfer-Encoding");
      } else {
        requestBuilder.header("Transfer-Encoding", "chunked");
        requestBuilder.removeHeader("Content-Length");
      }

      request = requestBuilder.build();
    }

 이것 은 함수 의 첫 번 째 부분 으로 주로 RequestBody 의 일부 메타 데 이 터 를 Header 의 첫 번 째 부분 에 복사 한 것 으로 주로 Content-TypeTransfer-Encoding 이다.Content-Type 은 모두 가 알 고 있 을 것 이 라 고 믿 습 니 다.RequestBody 을 표시 하 는 Mime-Type 의 형식 은 / 이 고 예 를 들 어 text/xml 입 니 다.한편,Transfer-Encoding 은 인터넷 전송 방식 을 나타 내 는데 구체 적 으로 알 고 싶 은 학생 들 은 이 링크 점 을 볼 수 있 습 니 다.
오류 가 발생 했 습 니 다.다시 시도 하 십시오.
// Create the initial HTTP engine. Retries and redirects need new engine for each attempt.
    //        http   ,               
    engine = new HttpEngine(client, request, false, false, forWebSocket, null, null, null, null);

    int followUpCount = 0; //      
    while (true) {
      if (canceled) { //      
        engine.releaseConnection();
        throw new IOException("Canceled");
      }

      try {
        engine.sendRequest();
        engine.readResponse();
      } catch (RequestException e) {
        // The attempt to interpret the request failed. Give up.
        throw e.getCause();
      } catch (RouteException e) {
        // The attempt to connect via a route failed. The request will not have been sent.
        HttpEngine retryEngine = engine.recover(e); //    
        if (retryEngine != null) {
          engine = retryEngine;
          continue;
        }
        // Give up; recovery is not possible.
        throw e.getLastConnectException();
      } catch (IOException e) {
        // An attempt to communicate with a server failed. The request may have been sent.
        HttpEngine retryEngine = engine.recover(e, null);
        if (retryEngine != null) {
          engine = retryEngine;
          continue;
        }

        // Give up; recovery is not possible.
        throw e;
      }
      .......

 이 코드 에서 OkHttpHttpEngine 대상 을 구축 하여 Http 등급 의 요청 의 발송 과 답장 의 수신 을 책임 지고 HttpEngine 은 이후 의 박문 에서 상세 하 게 설명 할 것 이다.그 다음 에 while 순환 에 들 어 갔 는데 이 순환 은 주로 방향 을 바 꾸 는 문 제 를 처리 하 는 것 이다.우 리 는 이 절 에서 주로 catch 의 논 리 를 주목 하 는데 이것 은 오류 재 시 를 처리 하 는 논리 이다.외층 에 while 순환 이 있 기 때문에 catch 에서 retryEngine 을 얻 으 려 고 시 도 했 고 있 으 면 continue,없 으 면 이상 을 던 졌 다.
재 정립 처리
Response response = engine.getResponse();
      // followUp     http connection      ?
      Request followUp = engine.followUpRequest();

      if (followUp == null) {
        if (!forWebSocket) { //    followup      websocket
          engine.releaseConnection();//    
        }
        return response;
      }

      if (++followUpCount > MAX_FOLLOW_UPS) {
        throw new ProtocolException("Too many follow-up requests: " + followUpCount);
      }

      if (!engine.sameConnection(followUp.httpUrl())) { //  followup httpUrl       ,   
        //schema,host or port      
        engine.releaseConnection();
      }
      //       connection !!!!
      Connection connection = engine.close();
      request = followUp;
      //    ,        
      engine = new HttpEngine(client, request, false, false, forWebSocket, connection, null, null,
          response);

여기 서 우 리 는 Http 의 방향 을 바 꾸 는 체 제 를 볼 수 있다.Request request = engine.followUpRequest() 으로 방향 을 바 꾸 려 면 보 내야 할 Request 을 얻 을 수 있 습 니 다.없 거나 방향 을 바 꾸 는 횟수 가 MAX_FOLLOW_UPS 보다 많 으 면 방향 변경 요 구 를 다시 보 내지 않 습 니 다.그리고 리 셋 요청 과 원래 요청 한 HttpUrl 이 같은 지 판단 합 니 다.그렇지 않 으 면 리 셋 요청 을 보 내지 않 습 니 다.그 다음 에 Connection connection = engine.close() 은 자원 을 방출 하고 지난번 연결 을 재 활용 한 다음 에 HttpEngine 을 새로 만 든 다음 에 While 순환 으로 요청 을 보 냅 니 다.
리 셋 상태 코드 분석
  public Request followUpRequest() throws IOException {
    if (userResponse == null) throw new IllegalStateException();
    Proxy selectedProxy = getRoute() != null
        ? getRoute().getProxy()
        : client.getProxy();
    int responseCode = userResponse.code();

    switch (responseCode) {
      case HTTP_PROXY_AUTH: //407 Proxy authentication required            
        if (selectedProxy.type() != Proxy.Type.HTTP) {
          throw new ProtocolException("Received HTTP_PROXY_AUTH (407) code while not using proxy");
        }
        // fall-through
      case HTTP_UNAUTHORIZED: //401       
        return OkHeaders.processAuthHeader(client.getAuthenticator(), userResponse, selectedProxy);

      case HTTP_PERM_REDIRECT:// 308
      case HTTP_TEMP_REDIRECT: //307
        // "If the 307 or 308 status code is received in response to a request other than GET
        // or HEAD, the user agent MUST NOT automatically redirect the request"
        if (!userRequest.method().equals("GET") && !userRequest.method().equals("HEAD")) {
            return null;
        } //    get head          
        // fall-through
      case HTTP_MULT_CHOICE: //300
      case HTTP_MOVED_PERM:// 301
      case HTTP_MOVED_TEMP://302
      case HTTP_SEE_OTHER: //303
        // Does the client allow redirects?
        if (!client.getFollowRedirects()) return null;//        

        String location = userResponse.header("Location");// response      location
        if (location == null) return null;
        HttpUrl url = userRequest.httpUrl().resolve(location);//  request   location

        // Don't follow redirects to unsupported protocols.
        if (url == null) return null;

        // If configured, don't follow redirects between SSL and non-SSL.
        boolean sameScheme = url.scheme().equals(userRequest.httpUrl().scheme());
        if (!sameScheme && !client.getFollowSslRedirects()) return null;

        // Redirects don't include a request body.
        Request.Builder requestBuilder = userRequest.newBuilder();
        if (HttpMethod.permitsRequestBody(userRequest.method())) {
          requestBuilder.method("GET", null);
          requestBuilder.removeHeader("Transfer-Encoding");
          requestBuilder.removeHeader("Content-Length");
          requestBuilder.removeHeader("Content-Type");
        }

        // When redirecting across hosts, drop all authentication headers. This
        // is potentially annoying to the application layer since they have no
        // way to retain them.
        if (!sameConnection(url)) {
          requestBuilder.removeHeader("Authorization");
        }

        return requestBuilder.url(url).build();

      default:
        return null;
    }

『8195』이 부분 은 답장 의 상태 코드 에 따라 재 설정 요청 코드 논 리 를 생 성 하 는 것 입 니 다.
  • HTTP_PROXY_AUTH 407 은 프 록 시 인증 이 필요 하 다 고 밝 혔 으 며,이때 이상 을 던 져
  • 으로 재 설정 하지 않 았 다.
  • HTTP_UNAUTHORIZED 401 신분 미 인증
  • HTTP_PERM_REDIRECT 308 HTTP_TEMP_REDIRECT 307 이 두 가지 상태 코드 는 요청 한 methodGETHEAD 이 아 닐 때 만 방향 을 바 꾸 지 않 으 며,그렇지 않 으 면 아래 열 상태 코드 로
  • 을 처리 합 니 다.
  • HTTP_MULT_CHOICE 300 HTTP_MOVED_PERM 301 HTTP_MOVED_TEMP 302 HTTP_SEE_OTHER 303 은 이러한 상태 코드 일 때 리 셋 실행 여 부 를 먼저 판단 한 뒤 ResponseLocation 첫 번 째 부분의 값 을 획득 한 뒤 HttpUrl 으로 해석 하고,host 이 다르다 면 모든 인증 첫 번 째 부분 을 제거 하 는 것 은 안전 을 위 한 것 이다.

  • 결어
     오늘 총 결 된 것 은 Http 의 재 정립 부분 과 OkHttp 중의 재 정립 에 관 한 논리 부분 일 뿐이다.그 후에 Http 에 관 한 지식 을 계속 정리 할 것 이다.『8195』본문 도 나의 독립 박문 에서 동시에 나 를 발표 했다.

    좋은 웹페이지 즐겨찾기