2015-09-11 4 views
212

J'essaie d'obtenir le JSON exact qui est envoyé dans la demande. Voici mon code:Connexion avec Retrofit 2

OkHttpClient client = new OkHttpClient(); 
client.interceptors().add(new Interceptor(){ 
    @Override public com.squareup.okhttp.Response intercept(Chain chain) throws IOException { 
     Request request = chain.request(); 
     Log.e(String.format("\nrequest:\n%s\nheaders:\n%s", 
          request.body().toString(), request.headers())); 
     com.squareup.okhttp.Response response = chain.proceed(request); 
     return response; 
    } 
}); 
Retrofit retrofit = new Retrofit.Builder() 
    .baseUrl(API_URL) 
    .addConverterFactory(GsonConverterFactory.create()) 
    .client(client).build(); 

Mais je ne vois que cela dans les journaux:

request: 
[email protected] 
headers: 
Content-Type: application/vnd.ll.event.list+json 

Comment suis-je censé faire l'exploitation forestière appropriée, compte tenu de la suppression des setLog() et setLogLevel() que nous avons utilisé à utiliser avec Rénovation 1?

Répondre

457

Dans Retrofit 2 vous devez utiliser HttpLoggingInterceptor.

Ajouter la dépendance à l'build.gradle:

compile 'com.squareup.okhttp3:logging-interceptor:3.9.1' 

Créer un objet Retrofit comme ce qui suit:

HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(); 
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY); 
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build(); 

Retrofit retrofit = new Retrofit.Builder() 
     .baseUrl("https://backend.example.com") 
     .client(client) 
     .addConverterFactory(GsonConverterFactory.create()) 
     .build(); 

return retrofit.create(ApiClient.class); 

La solution ci-dessus vous donne LogCat des messages très similaires aux anciens fixés par

setLogLevel(RestAdapter.LogLevel.FULL) 

Dans le cas de java.lang.ClassNotFoundException:

Une ancienne version Retrofit peut nécessiter une ancienne version logging-interceptor. Jetez un coup d'œil aux sections des commentaires pour plus de détails.

+20

Cela a été ajouté à OkHttp seulement 15 jours après ma question, sympa que la communauté a besoin d'un impact si rapide! – Gabor

+0

Je suis juste prendre cette erreur: 'Impossible de résoudre: om.squareup.okhttp: logging-interceptor: 2.6.0-SNAPSHOT' Quel est le problème? –

+0

@YuriyKolbasinskiy Vérifiez que vous avez ajouté 'maven {url 'http://oss.sonatype.org/content/repositories/snapshots'}' – GuillermoMP

-10

hey les gars, je trouve déjà la solution:

public static <T> T createApi(Context context, Class<T> clazz, String host, boolean debug) { 
    if (singleton == null) { 
     synchronized (RetrofitUtils.class) { 
      if (singleton == null) { 
       RestAdapter.Builder builder = new RestAdapter.Builder(); 
       builder 
         .setEndpoint(host) 
         .setClient(new OkClient(OkHttpUtils.getInstance(context))) 
         .setRequestInterceptor(RequestIntercepts.newInstance()) 
         .setConverter(new GsonConverter(GsonUtils.newInstance())) 
         .setErrorHandler(new ErrorHandlers()) 
         .setLogLevel(debug ? RestAdapter.LogLevel.FULL : RestAdapter.LogLevel.NONE)/*LogLevel.BASIC will cause response.getBody().in() close*/ 
         .setLog(new RestAdapter.Log() { 
          @Override 
          public void log(String message) { 
           if (message.startsWith("{") || message.startsWith("[")) 
            Logger.json(message); 
           else { 
            Logger.i(message); 
           } 
          } 
         }); 
       singleton = builder.build(); 
      } 
     } 
    } 
    return singleton.create(clazz); 
} 
+0

rappel de setLog peut entrer chaque log –

+0

est d'utiliser retrofit v1, v2 ne – Gabor

+0

Est-ce que ce travail pour Retrofit2? –

4

Je ne sais pas si setLogLevel() retourne dans la version 2.0 finale de Retrofit mais pour vous pouvez maintenant utiliser un intercepteur pour l'exploitation forestière.

Un bon exemple peut retrouver dans wiki OkHttp: https://github.com/square/okhttp/wiki/Interceptors

OkHttpClient client = new OkHttpClient(); 
client.interceptors().add(new LoggingInterceptor()); 

Retrofit retrofit = new Retrofit.Builder() 
     .baseUrl("http://www.yourjsonapi.com") 
     .addConverterFactory(GsonConverterFactory.create()) 
     .client(client) 
     .build(); 
+0

soit vous n'avez pas lu ma question ou n'avez pas lu la page que vous liez ... car LoggingInterceptor n'essaie pas d'enregistrer le corps de la requête (et donc ne résout pas mon problème) – Gabor

+0

Je reçois 'UnsupportedOperationException' – Choletski

5

Essayez ceci:.

Request request = chain.request(); 
Buffer buffer = new Buffer(); 
request.body().writeTo(buffer); 
String body = buffer.readUtf8(); 

Après cela, dans le body il y a le JSON vous êtes intéressé par

+1

comment imprimer la réponse du corps? –

+3

@GilbertoIbarra utiliser 'String bodyString = response.body(). String(); \t \t \t \t log (bodyString); response = response.newBuilder(). Corps (ResponseBody.create (response.body(). ContentType(), bodyString)). Build(); '(Vous ne pouvez pas lire le corps de la réponse plus d'une fois, donc vous devrez créer une nouvelle réponse avec le constructeur) –

+0

C'est une béquille dont nous n'avons pas besoin de plus. Voici un exemple de journalisation de travail: http://stackoverflow.com/a/36847027/2557258 – Yazon2006

9

Voici un Interceptor qui enregistre à la fois les corps de requête et de réponse (en utilisant Timber, basé sur un exemple des docs OkHttp et d'autres SO réponses):

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

     long t1 = System.nanoTime(); 
     Timber.i("Sending request %s on %s%n%s", request.url(), chain.connection(), request.headers()); 
     Timber.v("REQUEST BODY BEGIN\n%s\nREQUEST BODY END", bodyToString(request)); 

     Response response = chain.proceed(request); 

     ResponseBody responseBody = response.body(); 
     String responseBodyString = response.body().string(); 

     // now we have extracted the response body but in the process 
     // we have consumed the original reponse and can't read it again 
     // so we need to build a new one to return from this method 

     Response newResponse = response.newBuilder().body(ResponseBody.create(responseBody.contentType(), responseBodyString.getBytes())).build(); 

     long t2 = System.nanoTime(); 
     Timber.i("Received response for %s in %.1fms%n%s", response.request().url(), (t2 - t1)/1e6d, response.headers()); 
     Timber.v("RESPONSE BODY BEGIN:\n%s\nRESPONSE BODY END", responseBodyString); 

     return newResponse; 
    } 

    private static String bodyToString(final Request request){ 

     try { 
      final Request copy = request.newBuilder().build(); 
      final Buffer buffer = new Buffer(); 
      copy.body().writeTo(buffer); 
      return buffer.readUtf8(); 
     } catch (final IOException e) { 
      return "did not work"; 
     } 
    } 
} 
+0

voici un exemple plus facile: http://stackoverflow.com/a/36847027/2557258 – Yazon2006

+0

c'était exactement ce que je cherchais THX! – Informatic0re

+0

cela ne fonctionne pas pour plusieurs intercepteurs – abbath0767

4

Pour ceux qui ont besoin de l'exploitation forestière de haut niveau dans Retrofit, utilisez l'intercepteur comme celui-ci

public static class LoggingInterceptor implements Interceptor { 
    @Override public Response intercept(Chain chain) throws IOException { 
     Request request = chain.request(); 
     long t1 = System.nanoTime(); 
     String requestLog = String.format("Sending request %s on %s%n%s", 
       request.url(), chain.connection(), request.headers()); 
     //YLog.d(String.format("Sending request %s on %s%n%s", 
     //  request.url(), chain.connection(), request.headers())); 
     if(request.method().compareToIgnoreCase("post")==0){ 
      requestLog ="\n"+requestLog+"\n"+bodyToString(request); 
     } 
     Log.d("TAG","request"+"\n"+requestLog); 

     Response response = chain.proceed(request); 
     long t2 = System.nanoTime(); 

     String responseLog = String.format("Received response for %s in %.1fms%n%s", 
       response.request().url(), (t2 - t1)/1e6d, response.headers()); 

     String bodyString = response.body().string(); 

     Log.d("TAG","response"+"\n"+responseLog+"\n"+bodyString); 

     return response.newBuilder() 
       .body(ResponseBody.create(response.body().contentType(), bodyString)) 
       .build(); 
     //return response; 
    } 
} 

public static String bodyToString(final Request request) { 
    try { 
     final Request copy = request.newBuilder().build(); 
     final Buffer buffer = new Buffer(); 
     copy.body().writeTo(buffer); 
     return buffer.readUtf8(); 
    } catch (final IOException e) { 
     return "did not work"; 
    } 
}` 

Courtoisie: https://github.com/square/retrofit/issues/1072#

+0

vous devriez avoir mentionné que vous avez copié de https://github.com/square/retrofit/issues/1072# (pour donner crédit à votre source) – Gabor

+0

C'est une béquille dont nous n'avons pas besoin de plus. Voici un exemple de journalisation de travail: http://stackoverflow.com/a/36847027/2557258 – Yazon2006

24

j'ai rencontré la chose que vous et moi avons essayé de demander à l'auteur du livre Rénovation: Vous aimez travailler avec les API sur Android (voici le link) (Nope Je ne fais pas des annonces pour eux! ....mais ils sont vraiment gentils :) Et l'auteur m'a répondu très bientôt, avec la méthode Log sur Retrofit 1.9 et Retrofit 2.0-beta.

Et voici le code de Retrofit 2.0 beta:

HttpLoggingInterceptor logging = new HttpLoggingInterceptor(); 
// set your desired log level 
logging.setLevel(Level.BODY); 

OkHttpClient httpClient = new OkHttpClient(); 
// add your other interceptors … 

// add logging as last interceptor 
httpClient.interceptors().add(logging); // <-- this is the important line! 

Retrofit retrofit = new Retrofit.Builder() 
    .baseUrl(API_BASE_URL) 
    .addConverterFactory(GsonConverterFactory.create()) 
    .client(httpClient) 
    .build(); 

Voici comment ajouter la méthode d'enregistrement avec l'aide de HttpLoggingInterceptor. Aussi si vous êtes le lecteur de ce livre que j'ai mentionné ci-dessus, vous trouverez peut-être qu'il n'y a plus de méthode log avec Retrofit 2.0 - ce que j'avais demandé à l'auteur n'est pas correct et ils mettront à jour le livre l'année prochaine à propos de ça.

// Si vous n'êtes pas familier avec la méthode Log dans Retrofit, j'aimerais partager quelque chose de plus.

Notez également qu'il existe des niveaux de journalisation que vous pouvez sélectionner. J'utilise le Level.BODY la plupart du temps, ce qui donnera quelque chose comme ceci:

enter image description here

Vous pouvez trouver presque tout le personnel http dans l'image: l'en-tête, le contenu et la réponse,

Et parfois, vous n'avez vraiment pas besoin de tous les invités pour assister à votre fête: je veux juste savoir si elle est connectée avec succès, que l'appel d'Internet est réussi avec & Fragmetn. Ensuite, vous êtes libre d'utiliser Level.BASIC, qui retournera quelque chose comme ceci:

enter image description here

Pouvez-vous trouver le code d'état 200 OK intérieur? C'est ça :)

Il y en a un autre, Level.HEADERS, qui ne retournera que l'en-tête du réseau. Ya bien sûr une autre photo ici:

enter image description here

C'est tout de l'affaire Exploitation forestière;)

Et je voudrais vous partager avec le tutoriel que j'ai appris beaucoup there. Ils ont un tas de super article parlant de presque tout ce qui concerne Retrofit, et ils continuent à mettre à jour le post, en même temps Retrofit 2.0 arrive. S'il vous plaît jeter un oeil à ces travaux, qui je pense vous permettra de gagner beaucoup de temps.

+0

D'où provient HttpLoggingInterceptor? – Radu

+4

En outre, cela ne fonctionne pas pour moi. httpClient.interceptors.add veut un com.squareup.okhttp.Interceptor et pas un okhttp3.logging.HttpLoggingInterceptor – Radu

+0

@Radu Quelle version de Retrofit êtes-vous? Votre gradle devrait avoir quelque chose comme ceci: compiler 'com.squareup.retrofit2: retrofit: 2.0.0-beta4' – peitek

3

Le principal problème auquel je faisais face était l'ajout dynamique d'en-têtes et la consignation dans le logcat de débogage. J'ai essayé d'ajouter deux intercepteurs. Un pour la journalisation et un pour l'ajout des en-têtes sur le pouce (autorisation de jeton). Le problème était que nous pouvions .addInterceptor ou .addNetworkInterceptor. Comme me l'a dit Jake Wharton: "Les intercepteurs de réseau viennent toujours après les intercepteurs d'application, voir https://github.com/square/okhttp/wiki/Interceptors".Voici donc par exemple travailler avec les en-têtes et les journaux:

OkHttpClient httpClient = new OkHttpClient.Builder() 
      //here we can add Interceptor for dynamical adding headers 
      .addNetworkInterceptor(new Interceptor() { 
       @Override 
       public Response intercept(Chain chain) throws IOException { 
        Request request = chain.request().newBuilder().addHeader("test", "test").build(); 
        return chain.proceed(request); 
       } 
      }) 
      //here we adding Interceptor for full level logging 
      .addNetworkInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)) 
      .build(); 

    Retrofit retrofit = new Retrofit.Builder() 
      .addConverterFactory(GsonConverterFactory.create(gsonBuilder.create())) 
      .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 
      .client(httpClient) 
      .baseUrl(AppConstants.SERVER_ADDRESS) 
      .build(); 
2

Vous pouvez également ajouter Stetho Facebook et regarder les traces de réseau dans Chrome: http://facebook.github.io/stetho/

final OkHttpClient.Builder builder = new OkHttpClient.Builder(); 
if (BuildConfig.DEBUG) { 
    builder.networkInterceptors().add(new StethoInterceptor()); 
} 

Ensuite, ouvrez "chrome: // inspecter" Chrome ...

0

J'ai trouvé moyen pour Imprimer Connexion Rénovation

OkHttpClient okHttpClient = new OkHttpClient.Builder() 
      .addInterceptor(new Interceptor() { 
       @Override 
       public Response intercept(Chain chain) throws IOException { 
        Request request = chain.request(); 
        if (BuildConfig.DEBUG) { 
         Log.e(getClass().getName(), request.method() + " " + request.url()); 
         Log.e(getClass().getName(), "" + request.header("Cookie")); 
         RequestBody rb = request.body(); 
         Buffer buffer = new Buffer(); 
         if (rb != null) 
          rb.writeTo(buffer); 
         LogUtils.LOGE(getClass().getName(), "Payload- " + buffer.readUtf8()); 
        } 
        return chain.proceed(request); 
       } 
      }) 
      .readTimeout(60, TimeUnit.SECONDS) 
      .connectTimeout(60, TimeUnit.SECONDS) 
      .build(); 

      iServices = new Retrofit.Builder() 
        .baseUrl("Your Base URL") 
        .client(okHttpClient) 
        .addConverterFactory(GsonConverterFactory.create()) 
        .build() 
        .create(Your Service Interface .class); 

Fonctionne pour moi.

4

Si vous utilisez Retrofit2 et okhttp3, vous devez savoir qu'Interceptor fonctionne par file d'attente. Alors ajoutez loggingInterceptor à la fin, après vos autres Interceptor:

HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(); 
     if (BuildConfig.DEBUG) 
      loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS); 

new OkHttpClient.Builder() 
       .connectTimeout(60, TimeUnit.SECONDS) 
       .readTimeout(60, TimeUnit.SECONDS) 
       .writeTimeout(60, TimeUnit.SECONDS) 
       .addInterceptor(new CatalogInterceptor(context))//first 
       .addInterceptor(new OAuthInterceptor(context))//second 
       .authenticator(new BearerTokenAuthenticator(context)) 
       .addInterceptor(loggingInterceptor)//third, log at the end 
       .build(); 
1

Une meilleure façon de faire ce droit dans Retrofit 2 est d'ajouter l'intercepteur de l'enregistreur comme networkInterceptor ceci affichera les en-têtes de réseau et vos en-têtes personnalisés trop . L'important est de se rappeler que l'intercepteur fonctionne comme une pile et que vous êtes sûr d'ajouter l'enregistreur à la fin de tout.

OkHttpClient.Builder builder = new OkHttpClient.Builder(); 
builder.addInterceptor(new MyCustomInterceptor()); 
builder.connectTimeout(60, TimeUnit.SECONDS); 
builder.readTimeout(60, TimeUnit.SECONDS); 
builder.writeTimeout(60, TimeUnit.SECONDS); 
// important line here 
builder.addNetworkInterceptor(LoggerInterceptor()); 
0

La plupart des réponses ici couvre presque tout sauf cet outil, l'un des moyens les plus cool de voir le journal.

Il s'agit de Facebook's Stetho. Ceci est l'outil superbe pour surveiller/connecter le trafic réseau de votre application sur google chrome. Vous pouvez également trouver here sur Github.

enter image description here

0

pour Retrofit 2.0.2 le code est comme

**HttpLoggingInterceptor logging = new HttpLoggingInterceptor(); 
     logging.setLevel(HttpLoggingInterceptor.Level.BODY); 
     OkHttpClient.Builder httpClient=new OkHttpClient.Builder(); 
     httpClient.addInterceptor(logging);** 


     if (retrofit == null) { 
      retrofit = new Retrofit.Builder() 
        .baseUrl(BASE_URL) 
        .addConverterFactory(GsonConverterFactory.create()) 
        **.client(httpClient.build())** 
        .build(); 
     }