Comment enregistrer le corps de la demande et de la réponse avec Retrofit-Android?

129

Je ne trouve pas de méthodes pertinentes dans l'API Retrofit pour la journalisation des corps de demande / réponse complets. J'attendais de l'aide dans le profileur (mais il ne propose que des méta-données sur la réponse). J'ai essayé de définir le niveau de journalisation dans le générateur, mais cela ne m'aide pas non plus:

RestAdapter adapter = (new RestAdapter.Builder()).
                setEndpoint(baseUrl).
                setRequestInterceptor(interceptor).
                setProfiler(profiler).
                setClient(client).
                setExecutors(MyApplication.getWebServiceThreadPool()).
                setLogLevel(LogLevel.FULL).
                setLog(new RestAdapter.Log() {
                    @Override
                    public void log(String msg) {
                        Log.i(TAG, msg);
                    }
                }).
                build();

EDIT: Ce code fonctionne maintenant. Je ne sais pas pourquoi cela ne fonctionnait pas plus tôt. Peut-être parce que j'utilisais une ancienne version de retrofit.

Jaguar
la source
Avez-vous déjà compris cela? La documentation dit que FULLc'est censé donner le corps, mais cela ne semble pas.
theblang
1
@mattblang: Je ne sais pas ce qui n'allait pas auparavant, mais ce code fonctionne maintenant.
Jaguar
Possible duplicata de Logging with Retrofit 2
bryant1410
La course instantanée a probablement gâché si cela ne fonctionnait pas plus tôt
deathangel908

Réponses:

91

J'ai utilisé setLogLevel(LogLevel.FULL).setLog(new AndroidLog("YOUR_LOG_TAG")), ça m'a aidé.
METTRE À JOUR.
Vous pouvez également essayer à des fins de débogage une utilisation retrofit.client.Responsecomme modèle de réponse

Alex Dzeshko
la source
2
AndroidLog, quelle classe est-ce?
theblang
Il est livré avec une bibliothèque Retrofit.
Alex Dzeshko
2
Je vois. Malheureusement, cela ne vous donne pas le response body, bien que cela indique dans le document qui LogLevel.FULL devrait vous donner le response body.
theblang
Cela peut être vu avec "YOUR_LOG_TAG" dans Android logcat sous l'onglet détaillé.
rajeesh
4
LogLevel.Full n'existe pas dans la rénovation 2
121

Rénovation 2.0 :

MISE À JOUR: @ par Marcus Pöhls

Connexion Retrofit 2

Retrofit 2 repose entièrement sur OkHttp pour toute opération réseau. Puisque OkHttp est une dépendance homologue de Retrofit 2, vous n'aurez pas besoin d'ajouter une dépendance supplémentaire une fois que Retrofit 2 sera publié en tant que version stable.

OkHttp 2.6.0 est livré avec un intercepteur de journalisation en tant que dépendance interne et vous pouvez l'utiliser directement pour votre client Retrofit. Retrofit 2.0.0-beta2 utilise toujours OkHttp 2.5.0. Les versions futures augmenteront la dépendance aux versions supérieures d'OkHttp. C'est pourquoi vous devez importer manuellement l'intercepteur de journalisation. Ajoutez la ligne suivante à vos importations gradle dans votre fichier build.gradle pour récupérer la dépendance de l'intercepteur de journalisation.

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

Vous pouvez également visiter la page GitHub de Square à propos de cet intercepteur

Ajouter la journalisation à la modernisation 2

Lors du développement de votre application et à des fins de débogage, il est agréable d'avoir une fonction de journal intégrée pour afficher les informations de demande et de réponse. La journalisation n'étant plus intégrée par défaut dans Retrofit 2, nous devons ajouter un intercepteur de journalisation pour OkHttp. Heureusement, OkHttp est déjà livré avec cet intercepteur et il vous suffit de l'activer pour votre OkHttpClient.

HttpLoggingInterceptor logging = new HttpLoggingInterceptor();  
// set your desired log level
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();   
// add your other interceptors …
// add logging as last interceptor
httpClient.addInterceptor(logging);  // <-- this is the important line!
Retrofit retrofit = new Retrofit.Builder()  
        .baseUrl(API_BASE_URL)
        .addConverterFactory(GsonConverterFactory.create())
        .client(httpClient.build())
        .build();

Nous vous recommandons d'ajouter la journalisation en tant que dernier intercepteur, car cela enregistrera également les informations que vous avez ajoutées avec les intercepteurs précédents à votre demande.

Niveaux de journal

Enregistrer trop d'informations fera exploser votre moniteur Android, c'est pourquoi l'intercepteur de journalisation d'OkHttp a quatre niveaux de journalisation: AUCUN, BASIC, EN-TÊTES, CORPS. Nous allons vous guider à travers chacun des niveaux de journal et décrire leur sortie.

Pour plus d'informations, veuillez consulter: Retrofit 2 - Log Requests and Responses

ANCIENNE RÉPONSE:

plus de connexion dans Retrofit 2. L'équipe de développement a supprimé la fonctionnalité de journalisation. Pour être honnête, la fonction de journalisation n'était de toute façon pas aussi fiable. Jake Wharton a explicitement déclaré que les messages ou objets enregistrés sont les valeurs supposées et qu'ils n'ont pas pu être prouvés comme étant vrais. La demande réelle qui arrive au serveur peut avoir un corps de demande modifié ou autre chose.

Même s'il n'y a pas de journalisation intégrée par défaut, vous pouvez tirer parti de n'importe quel enregistreur Java et l'utiliser dans un intercepteur OkHttp personnalisé.

plus d'informations sur Retrofit 2, veuillez consulter: Retrofit - Mise en route et création d'un client Android

Dhaval Jivani
la source
1
Il existe également un article spécifique pour la connexion à Retrofit 2.0: futurestud.io/blog/retrofit-2-log-requests-and-responses
peitek
Excellent moyen de tout rendre plus compliqué qu'il ne devrait l'être. Cela me rappelle la journalisation Jersey 1 vs Jersey 2. Plus de code passe
partout
L'ajout d'intercepteurs de cette manière entraînera désormais une exception UnsupportedOperationException dans OkHttp v3. La nouvelle façon est: OkHttpClient.Builder (). AddInterceptor (logging) .build () github.com/square/okhttp/issues/2219
Amagi82
@JawadLeWywadi oui en utilisant ce code, vous pouvez imprimer le corps
Dhaval Jivani
Pour Retrofit 2, c'est beaucoup plus facile.
Gary99
31

Mise à jour pour Retrofit 2.0.0-beta3

Vous devez maintenant utiliser okhttp3 avec builder. De plus, l'ancien intercepteur ne fonctionnera pas. Cette réponse est adaptée pour Android.

Voici un copier-coller rapide pour vous avec les nouveautés.

1. Modifiez votre fichier gradle en

  compile 'com.squareup.retrofit2:retrofit:2.0.0-beta3'
  compile "com.squareup.retrofit2:converter-gson:2.0.0-beta3"
  compile "com.squareup.retrofit2:adapter-rxjava:2.0.0-beta3"
  compile 'com.squareup.okhttp3:logging-interceptor:3.0.1'

2. Vérifiez cet exemple de code:

avec les nouvelles importations. Vous pouvez supprimer Rx si vous ne l'utilisez pas, supprimez également ce que vous n'utilisez pas.

import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.GsonConverterFactory;
import retrofit2.Retrofit;
import retrofit2.RxJavaCallAdapterFactory;
import retrofit2.http.GET;
import retrofit2.http.Query;
import rx.Observable;

public interface APIService {

  String ENDPOINT = "http://api.openweathermap.org";
  String API_KEY = "2de143494c0b2xxxx0e0";

  @GET("/data/2.5/weather?appid=" + API_KEY) Observable<WeatherPojo> getWeatherForLatLon(@Query("lat") double lat, @Query("lng") double lng, @Query("units") String units);


  class Factory {

    public static APIService create(Context context) {

      OkHttpClient.Builder builder = new OkHttpClient().newBuilder();
      builder.readTimeout(10, TimeUnit.SECONDS);
      builder.connectTimeout(5, TimeUnit.SECONDS);

      if (BuildConfig.DEBUG) {
        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.setLevel(HttpLoggingInterceptor.Level.BASIC);
        builder.addInterceptor(interceptor);
      }

      //Extra Headers

      //builder.addNetworkInterceptor().add(chain -> {
      //  Request request = chain.request().newBuilder().addHeader("Authorization", authToken).build();
      //  return chain.proceed(request);
      //});

      builder.addInterceptor(new UnauthorisedInterceptor(context));
      OkHttpClient client = builder.build();

      Retrofit retrofit =
          new Retrofit.Builder().baseUrl(APIService.ENDPOINT).client(client).addConverterFactory(GsonConverterFactory.create()).addCallAdapterFactory(RxJavaCallAdapterFactory.create()).build();

      return retrofit.create(APIService.class);
    }
  }
}

Prime

Je sais que c'est hors sujet mais je trouve ça cool.

Dans le cas où il y aurait un code d'erreur http non autorisé , voici un intercepteur. J'utilise eventbus pour transmettre l'événement.

import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import com.androidadvance.ultimateandroidtemplaterx.BaseApplication;
import com.androidadvance.ultimateandroidtemplaterx.events.AuthenticationErrorEvent;

import de.greenrobot.event.EventBus;
import java.io.IOException;
import javax.inject.Inject;
import okhttp3.Interceptor;
import okhttp3.Response;

public class UnauthorisedInterceptor implements Interceptor {

  @Inject EventBus eventBus;

  public UnauthorisedInterceptor(Context context) {
    BaseApplication.get(context).getApplicationComponent().inject(this);
  }

  @Override public Response intercept(Chain chain) throws IOException {
    Response response = chain.proceed(chain.request());
    if (response.code() == 401) {
      new Handler(Looper.getMainLooper()).post(() -> eventBus.post(new AuthenticationErrorEvent()));
    }
    return response;
  }
}

code extrait de https://github.com/AndreiD/UltimateAndroidTemplateRx (mon projet).

OWADVL
la source
9

Il ne semble pas y avoir de moyen de faire basic + body, mais vous pouvez utiliser FULL et filtrer les en-têtes que vous ne voulez pas.

RestAdapter adapter = new RestAdapter.Builder()
                          .setEndpoint(syncServer)
                          .setErrorHandler(err)
                          .setConverter(new GsonConverter(gson))
                          .setLogLevel(logLevel)
                          .setLog(new RestAdapter.Log() {
                              @Override
                              public void log(String msg) {
                                  String[] blacklist = {"Access-Control", "Cache-Control", "Connection", "Content-Type", "Keep-Alive", "Pragma", "Server", "Vary", "X-Powered-By"};
                                  for (String bString : blacklist) {
                                      if (msg.startsWith(bString)) {
                                          return;
                                      }
                                  }
                                  Log.d("Retrofit", msg);
                              }
                          }).build();

Il semble que lors du remplacement du journal, le corps est précédé d'une balise similaire à

[ 02-25 10:42:30.317 25645:26335 D/Retrofit ]

il devrait donc être facile de consigner le corps de base + en ajustant le filtre personnalisé. J'utilise une liste noire, mais une liste blanche peut également être utilisée en fonction de vos besoins.

Xeridea
la source
4

le code ci-dessous fonctionne à la fois avec en-tête et sans en-tête pour imprimer la demande et la réponse du journal. Remarque: il suffit de commenter la ligne .addHeader () si vous n'utilisez pas d'en-tête.

HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        OkHttpClient client = new OkHttpClient.Builder()
                .addInterceptor(interceptor)
                //.addInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR)
                .addNetworkInterceptor(new Interceptor() {

                    @Override

                    public okhttp3.Response intercept(Chain chain) throws IOException {
                        Request request = chain.request().newBuilder()
                                // .addHeader(Constant.Header, authToken)
                                   .build();
                        return chain.proceed(request);
                    }
                }).build();

        final Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(Constant.baseUrl)
                .client(client) // This line is important
                .addConverterFactory(GsonConverterFactory.create())
                .build();
Mukesh Parmar
la source
3

J'espère que ce code vous aidera à vous connecter.
il vous suffit d'ajouter un intercepteur dans votre Build.Gradlemake RetrofitClient.

Premier pas

Ajoutez cette ligne à votre build.gradle

 implementation 'com.squareup.okhttp3:logging-interceptor:3.4.1' 

Deuxième étape

Faites votre client de rénovation


   public class RetrofitClient {

    private Retrofit retrofit;
    private static OkHttpClient.Builder httpClient =
            new OkHttpClient.Builder();
    private static RetrofitClient instance = null;
    private static ApiServices service = null;
    private static HttpLoggingInterceptor logging =
            new HttpLoggingInterceptor();

    private RetrofitClient(final Context context) {
        httpClient.interceptors().add(new Interceptor() {
            @Override
            public okhttp3.Response intercept(Interceptor.Chain chain) throws IOException {
                Request originalRequest = chain.request();
                Request.Builder builder = originalRequest.newBuilder().
                        method(originalRequest.method(), originalRequest.body());
                okhttp3.Response response = chain.proceed(builder.build());
                /*
                Do what you want
                 */
                return response;
            }
        });

        if (BuildConfig.DEBUG) {
            logging.setLevel(HttpLoggingInterceptor.Level.BODY);
            // add logging as last interceptor
            httpClient.addInterceptor(logging);
        }

        retrofit = new Retrofit.Builder().client(httpClient.build()).
                baseUrl(Constants.BASE_URL).
                addConverterFactory(GsonConverterFactory.create()).build();
        service = retrofit.create(ApiServices.class);
    }


    public static RetrofitClient getInstance(Context context) {
        if (instance == null) {
            instance = new RetrofitClient(context);
        }
        return instance;
    }

    public ApiServices getApiService() {
        return service;
    }
}

Appel

RetrofitClient.getInstance(context).getApiService().yourRequestCall(); 
Talha Bilal
la source
2

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

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))
                .addInterceptor(new OAuthInterceptor(context))
                .authenticator(new BearerTokenAuthenticator(context))
                .addInterceptor(loggingInterceptor)//at the end
                .build();
NickUnuchek
la source