Jak zarejestrować treść żądania i odpowiedzi za pomocą Retrofit-Android?


129

Nie mogę znaleźć odpowiednich metod w interfejsie Retrofit API do rejestrowania pełnych treści żądania / odpowiedzi. Spodziewałem się pomocy w Profiler (ale oferuje tylko metadane dotyczące odpowiedzi). Próbowałem ustawić poziom dziennika w Kreatorze, ale to też mi nie pomaga:

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();

EDYCJA: Ten kod już działa. Nie wiem, dlaczego wcześniej nie działało. Prawdopodobnie dlatego, że korzystałem ze starszej wersji modernizacji.


Czy kiedykolwiek to rozgryzłeś? Dokumentacja mówi, że FULLma to dać ciało, ale wydaje się, że tak nie jest.
theblang

1
@mattblang: Nie wiem, co było wcześniej nie tak, ale ten kod teraz działa.
Jaguar



Prawdopodobnie natychmiastowe uruchomienie zepsuło coś, jeśli nie zadziałało wcześniej
deathangel908

Odpowiedzi:


91

Użyłem setLogLevel(LogLevel.FULL).setLog(new AndroidLog("YOUR_LOG_TAG")), pomogło mi.
AKTUALIZACJA.
Możesz także spróbować użyć do debugowania retrofit.client.Responsejako modelu odpowiedzi


2
AndroidLog, jaka to klasa?
theblang

Pochodzi z biblioteką Retrofit.
Alex Dzeshko

2
Widzę. Niestety to nie daje ci response body, chociaż stwierdza w dokumencie, który LogLevel.FULL powinien dać ci response body.
theblang

Można to zobaczyć po wpisaniu „YOUR_LOG_TAG” w logcat Androida na karcie pełnej informacji.
rajeesh

4
LogLevel.Full nie istnieje w modernizacji 2

121

Modernizacja 2.0 :

AKTUALIZACJA: @ by Marcus Pöhls

Logowanie się Retrofit 2

Retrofit 2 całkowicie opiera się na OkHttp dla dowolnej operacji w sieci. Ponieważ OkHttp jest zależnością równorzędną Retrofit 2, nie musisz dodawać dodatkowej zależności po wydaniu Retrofit 2 jako stabilnej wersji.

OkHttp 2.6.0 jest dostarczany z przechwytywaczem logów jako wewnętrzną zależnością i możesz go bezpośrednio użyć dla swojego klienta Retrofit. Retrofit 2.0.0-beta2 nadal używa OkHttp 2.5.0. Przyszłe wydania podbiją zależność do wyższych wersji OkHttp. Dlatego musisz ręcznie zaimportować przechwytywacz rejestrowania. Dodaj następujący wiersz do importu gradle w pliku build.gradle, aby pobrać zależność przechwytywacza rejestrowania.

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

Możesz również odwiedzić stronę Square GitHub dotyczącą tego przechwytywacza

Dodaj rejestrowanie do modernizacji 2

Podczas tworzenia aplikacji i do celów debugowania dobrze jest mieć zintegrowaną funkcję dziennika, która wyświetla informacje o żądaniach i odpowiedziach. Ponieważ rejestrowanie nie jest już domyślnie zintegrowane w Retrofit 2, musimy dodać przechwytywacz rejestrowania dla OkHttp. Na szczęście OkHttp jest już dostarczany z tym przechwytywaczem i musisz go tylko aktywować dla swojego 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();

Zalecamy dodanie rejestrowania jako ostatniego przechwytywacza, ponieważ będzie to również rejestrować informacje, które dodałeś do poprzedniego przechwytywania do żądania.

Log Levels

Rejestrowanie zbyt dużej ilości informacji spowoduje wysadzenie monitora Android, dlatego przechwytywacz logowania OkHttp ma cztery poziomy logowania: BRAK, PODSTAWOWY, NAGŁÓWKI, CIAŁO. Przeprowadzimy Cię przez każdy z poziomów dziennika i opiszemy ich wyniki.

Więcej informacji: Retrofit 2 - Log Requests and Responses

STARA ODPOWIEDŹ:

brak logowania Retrofit 2 już. Zespół programistów usunął funkcję rejestrowania. Szczerze mówiąc, funkcja rejestrowania i tak nie była tak niezawodna. Jake Wharton wyraźnie stwierdził, że zarejestrowane wiadomości lub obiekty są wartościami założonymi i nie można ich udowodnić, że są prawdziwe. Faktyczne żądanie, które dociera do serwera, może mieć zmienioną treść żądania lub coś innego.

Mimo że domyślnie nie ma zintegrowanego rejestrowania, można wykorzystać dowolny rejestrator Java i używać go w dostosowanym przechwytywaczu OkHttp.

Więcej informacji na temat Retrofit 2 można znaleźć w: Retrofit - Getting Started and Create an Android Client


1
Jest też post specyficzny dla logowania w Retrofit 2.0: futurestud.io/blog/retrofit-2-log-requests-and-responses
peitek

Świetny sposób, aby wszystko było bardziej skomplikowane niż powinno. Przypomina mi logowanie Jersey 1 do Jersey 2. Więcej kodu standardowego ....
breakline

Dodanie przechwytywaczy w ten sposób spowoduje teraz wyjątek UnsupportedOperationException w OkHttp v3. Nowy sposób to: OkHttpClient.Builder (). AddInterceptor (logowanie) .build () github.com/square/okhttp/issues/2219
Amagi82

@JawadLeWywadi tak, używając tego kodu możesz wydrukować ciało
Dhaval Jivani

Dla Retrofit 2, to jest o wiele łatwiejsze.
Gary99,

31

Aktualizacja dla Retrofit 2.0.0-beta3

Teraz musisz użyć okhttp3 z konstruktorem. Również stary przechwytywacz nie będzie działał. Ta odpowiedź jest dostosowana do Androida.

Oto szybkie kopiowanie wklejania z nowymi elementami.

1. Zmodyfikuj plik gradle na

  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. Sprawdź ten przykładowy kod:

z nowym importem. Możesz usunąć Rx, jeśli go nie używasz, a także usunąć to, czego nie używasz.

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);
    }
  }
}

Premia

Wiem, że to offtopic, ale uważam to za fajne.

W przypadku nieautoryzowanego kodu błędu http , oto przechwytywacz. Do transmisji zdarzenia używam magistrali eventbus.

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;
  }
}

kod pochodzi z https://github.com/AndreiD/UltimateAndroidTemplateRx (mój projekt).


9

Wygląda na to, że nie ma sposobu na zrobienie basic + body, ale możesz użyć FULL i filtrować nagłówki, których nie chcesz.

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();

Wygląda na to, że podczas nadpisywania dziennika treść jest poprzedzona tagiem podobnym do

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

więc rejestrowanie treści basic + body powinno być łatwe, dostosowując niestandardowy filtr. Używam czarnej listy, ale w zależności od potrzeb można również użyć białej listy.


4

poniższy kod działa zarówno z nagłówkiem, jak i bez nagłówka, aby wydrukować żądanie dziennika i odpowiedź. Uwaga: Po prostu skomentuj wiersz .addHeader (), jeśli nie używasz nagłówka.

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();

3

Mam nadzieję, że ten kod pomoże Ci się zalogować.
wystarczy, że dodasz przechwytywacz w swojej Build.Gradleprodukcji RetrofitClient.

Pierwszy krok

Dodaj tę linię do swojego build.gradle

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

Drugi krok

Stwórz swojego klienta modernizacji


   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;
    }
}

Powołanie

RetrofitClient.getInstance(context).getApiService().yourRequestCall(); 

2

Jeśli używasz Retrofit2 i okhttp3, musisz wiedzieć, że Interceptor działa w kolejce. Więc dodaj loggingInterceptor na końcu, po innych Interceptorach:

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();


Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.