2015-09-19 5 views
6

私は、アプリケーションのネットワーク要求を行うためにRetrofitでOkHttpを使用しています。また、必要に応じて、認証用のインターセプタとリクエストの再試行も使用しています。OKHttpインターセプタからエラーを返す(改造を使用)

サーバには一時的な問題があり、応答ステータスが200 OKであるにもかかわらず空のボディを返すことがあります。 Retrofitコールバックの成功ブロックが呼び出され、返された(およびGSONで解析された)カスタムオブジェクトがnullであり、成功コールバックのコードがオブジェクトが返されたと仮定しているため、これによりアプリケーションがクラッシュします。

これは既にサーバーチームに報告されていますが、すべての成功コールバックコードをヌルチェックですべてラップする必要はありません。

Currenty他のアイデアは大歓迎ですが、私は、二つのオプションに傾いています: 1)インターセプタから戻っていないが(これも可能です)だけエラーダイアログ 2を表示)レトロフィットを行います何かを返します?コールバックの失敗部分を呼び出します。

私のコードは以下の通りです。ご覧のとおり、空のボディを受け取った場合、最大3回のリクエストを再試行します。

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

    .... 
    .... 
    .... 

    // Retry empty body response requests for a maximum of 3 times 
    Integer retryMaxCount = 3; 
    MediaType contentType = response.body().contentType(); 
    String bodyString = response.body().string(); 

    while (bodyString.length() == 0 && retryMaxCount > 0) 
    { 
     //Empty body received!, Retrying... 

     retryMaxCount--; 
     response = chain.proceed(request); 
     bodyString = response.body().string(); 
    } 

    if (bodyString.length() != 0) 
    { 
     // Create and return new response because it was consumed 
     ResponseBody newResponseBody = ResponseBody.create(contentType, bodyString); 
     return response.newBuilder().body(newResponseBody).build(); 
    } 
    else 
    { 
     // WHAT TO WRITE HERE??? 
    } 
} 

ありがとうございます。

+8

なぜインターセプタから例外をスローしないのですか? – mastov

+3

ありがとうございました。それは簡単だった。あなたが答えとして投稿するなら、私はそれを受け入れるでしょう。 :) –

+0

@mastov あなたがエラーを投げた場合、あなたのアプリはクラッシュしませんか?どのようにエラーを処理する/それをコールバックに伝播するのですか? – Singed

答えて

0

ちょうど同じシナリオがあり、この記事はこのソリューションの実装に役立ちました。正しい方向を指す@mastovのおかげです。

エラーがあっても常にHTTP 200を返すバックエンドAPIを使用して作業します。これは私の応答のエラーサンプルでした

{"status":403,"message":"Bad User credentials","time":1495597740061,"version":"1.0"} 

この回答を補完する簡単な実装です。

public Response intercept(Chain chain) throws IOException { 
     Request request = chain.request(); 
     Response response = chain.proceed(request); 
     ResponseBody body = response.body(); 
     // Only intercept JSON type responses and ignore the rest. 
     if (body != null && body.contentType() != null && body.contentType().subtype() != null && body.contentType().subtype().toLowerCase().equals("json")) { 
      String errorMessage = ""; 
      int errorCode  = 200; // Assume default OK 
      try { 
       BufferedSource source = body.source(); 
       source.request(Long.MAX_VALUE); // Buffer the entire body. 
       Buffer buffer = source.buffer(); 
       Charset charset = body.contentType().charset(Charset.forName("UTF-8")); 
       // Clone the existing buffer is they can only read once so we still want to pass the original one to the chain. 
       String json  = buffer.clone().readString(charset); 
       JsonElement obj = new JsonParser().parse(json); 
       // Capture error code an message. 
       if (obj instanceof JsonObject && ((JsonObject) obj).has("status")) { 
        errorCode = ((JsonObject) obj).get("status").getAsInt(); 
       } 
       if (obj instanceof JsonObject && ((JsonObject) obj).has("message")) { 
        errorMessage= ((JsonObject) obj).get("message").getAsString(); 
       } 
      } catch (Exception e) { 
       Log.e(TAG, "Error: " + e.getMessage()); 
      } 
      // Check if status has an error code then throw and exception so retrofit can trigger the onFailure callback method. 
      // Anything above 400 is treated as a server error. 
      if(errorCode > 399){ 
       throw new Exception("Server error code: " + errorCode + " with error message: " + errorMessage); 
      } 
     } 

     return response; 
    } 
関連する問題