Registrazione con Retrofit 2


308

Sto cercando di ottenere l'esatto JSON che viene inviato nella richiesta. Ecco il mio codice:

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

Ma vedo solo questo nei registri:

request:
com.squareup.okhttp.RequestBody$1@3ff4074d
headers:
Content-Type: application/vnd.ll.event.list+json

Come dovrei fare una registrazione adeguata, data la rimozione setLog()e setLogLevel()che usavamo con Retrofit 1?

Risposte:


699

In Retrofit 2 dovresti usare HttpLoggingInterceptor .

Aggiungi dipendenza a build.gradle. L'ultima versione di ottobre 2019 è:

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

Crea un Retrofitoggetto come il seguente:

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

In caso di avvisi di deprecazione, è sufficiente passare setLevela:

interceptor.level(HttpLoggingInterceptor.Level.BODY);

La soluzione sopra ti dà messaggi logcat molto simili a quelli vecchi impostati da

setLogLevel(RestAdapter.LogLevel.FULL)

In caso dijava.lang.ClassNotFoundException :

La versione di Retrofit precedente potrebbe richiedere una logging-interceptorversione precedente . Dai un'occhiata alle sezioni dei commenti per i dettagli.


30
Questo è stato aggiunto a OkHttp solo 15 giorni dopo la mia domanda, bello che le esigenze della comunità abbiano un impatto così rapido!
Gabor,

1
e non è più necessario aggiungere il repository di snapshot sonatype al build.gradle
James Goodwin,

13
retrofit 2.1.0 usa questa compilazione 'com.squareup.okhttp3: logging-interceptor: 3.3.1'
jayellos

2
@jayellos Grazie per averlo indicato. Se si utilizza una versione precedente alla 3.3.1 non si otterrà tale eccezione al metodo.
guydemossyrock,

2
Ricevo: non hai trovato idea "okhttp3.internal.Platform"?
corlaez,

35

Ho incontrato la cosa come te e ho cercato di chiedere all'autore del libro Retrofit: Adoro lavorare con le API su Android (ecco il link ) (no! Non sto facendo annunci per loro .... ma sono davvero carini ragazzi :) E l'autore mi ha risposto molto presto, sia con il metodo Log su Retrofit 1.9 sia con Retrofit 2.0-beta.

Ed ecco il codice di 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();

Ecco come aggiungere il metodo di registrazione con l'aiuto di HttpLoggingInterceptor . Inoltre, se sei il lettore di quel libro che ho menzionato sopra, potresti scoprire che non esiste più un metodo di registro con Retrofit 2.0 - che, avevo chiesto all'autore, non è corretto e aggiorneranno il libro l'anno prossimo parlando a proposito.

// Nel caso in cui non abbiate familiarità con il metodo Log in Retrofit, vorrei condividere qualcosa in più.

Inoltre, va notato che ci sono alcuni livelli di registrazione che puoi scegliere. Uso Level.BODY il più delle volte, il che darà qualcosa del genere:

inserisci qui la descrizione dell'immagine

All'interno dell'immagine puoi trovare quasi tutto lo staff http: l'intestazione, il contenuto e la risposta, ecc.

E a volte non hai davvero bisogno di tutti gli ospiti per partecipare alla tua festa: voglio solo sapere se è collegato correttamente, che la chiamata via Internet è stata effettuata con successo all'interno di Activiy & Fragmetn. Quindi sei libero di usare Level.BASIC , che restituirà qualcosa del genere:

inserisci qui la descrizione dell'immagine

Riesci a trovare il codice di stato 200 OK all'interno? Questo è tutto :)

Inoltre ce n'è un altro, Level.HEADERS , che restituirà solo l'intestazione della rete. Certamente un'altra foto qui:

inserisci qui la descrizione dell'immagine

Questo è tutto il trucco di registrazione;)

E vorrei condividerti con il tutorial che ho imparato molto . Hanno un sacco di grandi post che parlano di quasi tutto ciò che riguarda Retrofit e stanno continuando ad aggiornare il post, allo stesso tempo Retrofit 2.0 sta arrivando. Per favore, dai un'occhiata a quei lavori, che penso ti faranno risparmiare un sacco di tempo.


Da dove proviene HttpLoggingInterceptor?
Radu,

5
Inoltre, questo non funziona per me. httpClient.interceptors.add vuole un com.squareup.okhttp.Interceptor e non un okhttp3.logging.HttpLoggingInterceptor
Radu

@Radu In quale versione di Retrofit sei su? Il tuo voto dovrebbe avere qualcosa del genere: compila 'com.squareup.retrofit2: retrofit: 2.0.0-beta4'
peitek,

Non funzionerebbe per la registrazione delle intestazioni delle richieste perché è necessario aggiungere Interceptor come intercettore di rete! Vedi: stackoverflow.com/a/36847027/2557258
Yazon2006

12

Ecco un esempio Interceptorche registra sia i corpi di richiesta che quelli di risposta (usando Timber, basato su un esempio dai documenti OkHttp e alcune altre risposte SO):

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

6

Prova questo:

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

Dopo questo, nel bodyc'è il JSON che ti interessa.


1
come può stampare la risposta del corpo?
Gilberto Ibarra,

3
@GilbertoIbarra use String bodyString = response.body().string(); log(bodyString); response = response.newBuilder().body(ResponseBody.create(response.body().contentType(), bodyString)).build(); (Non puoi leggere il corpo della risposta più di una volta, quindi dovrai creare una nuova risposta con il costruttore)
Anton Ryabyh,

È una stampella di cui non abbiamo bisogno di più. Ecco un esempio di registrazione di lavoro: stackoverflow.com/a/36847027/2557258
Yazon2006

6

Il problema principale che ho riscontrato è stato l'aggiunta dinamica di intestazioni e il loro log in logcat di debug. Ho provato ad aggiungere due intercettori. Uno per la registrazione e uno per l'aggiunta di intestazioni in movimento (autorizzazione token). Il problema era che potevamo .addInterceptor o .addNetworkInterceptor. Come mi ha detto Jake Wharton: "Gli intercettori di rete vengono sempre dopo intercettori di applicazioni. Vedi https://github.com/square/okhttp/wiki/Interceptors ". Quindi ecco un esempio funzionante con intestazioni e registri:

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

5

Non so se setLogLevel () tornerà nella versione 2.0 finale di Retrofit ma per ora è possibile utilizzare un intercettore per la registrazione.

Un buon esempio può essere trovato nella wiki di 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();

o non hai letto la mia domanda o non hai letto la pagina a cui stai collegando ... perché LoggingInterceptor non tenta di registrare il corpo della richiesta (e quindi non risolve il mio problema)
Gabor

Ottengo "UnsupportedOperationException"
Choletski il

5

Se stai usando Retrofit2 e okhttp3, devi sapere che Interceptor funziona in coda. Quindi aggiungi loggingInterceptor alla fine, dopo gli altri tuoi intercettori:

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

4

Per coloro che necessitano di logging di alto livello in Retrofit, utilizzare l'interceptor in questo modo

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

Per gentile concessione : https://github.com/square/retrofit/issues/1072#


avresti dovuto menzionare che hai copiato da github.com/square/retrofit/issues/1072# (per dare credito alla tua fonte)
Gabor

È una stampella di cui non abbiamo bisogno di più. Ecco un esempio di registrazione di lavoro: stackoverflow.com/a/36847027/2557258
Yazon2006

4

Codice di Kotlin

        val interceptor = HttpLoggingInterceptor()
        interceptor.level = HttpLoggingInterceptor.Level.BODY
        val client = OkHttpClient.Builder().addInterceptor(interceptor).build()
        val retrofit = Retrofit.Builder()
                .baseUrl(BASE_URL)
                .client(client)
                .addConverterFactory(GsonConverterFactory.create())
                .build()

        return retrofit.create(PointApi::class.java)

2

Puoi anche aggiungere Stetho di Facebook e guardare le tracce di rete in Chrome: http://facebook.github.io/stetho/

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

Quindi apri "chrome: // inspect" in Chrome ...


2

questo creerà un oggetto retrofit con Logging. senza creare oggetti separati.

 private static final Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(BASE_URL)
            .client(new OkHttpClient().newBuilder()
                    .addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
                    .readTimeout(READ_TIMEOUT_SECONDS, TimeUnit.SECONDS)
                    .writeTimeout(WRITE_TIMEOUT_SECONDS, TimeUnit.SECONDS)
                    .connectTimeout(CONNECTION_TIMEOUT_SECONDS, TimeUnit.SECONDS)
                    .build())
            .addConverterFactory(GsonConverterFactory.create())
            .build();

2

Per prima cosa aggiungi dipendenza a build.gradle:

implementazione 'com.squareup.okhttp3: logging-interceptor: 3.12.1'

Mentre usi Kotlin puoi aggiungere Logging Interceptor in questo modo:

companion object {
    val okHttpClient = OkHttpClient().newBuilder()
            .addInterceptor(HttpLoggingInterceptor().apply {
                level = HttpLoggingInterceptor.Level.BODY
            })
            .build()


    fun getRetrofitInstance(): Retrofit {
        val retrofit = Retrofit.Builder()
                .client(okHttpClient)
                .baseUrl(ScanNShopConstants.BASE_URL)
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .build()

        return retrofit
    }
}

2

Il seguente set di codice funziona senza problemi per me

Gradle

// Retrofit
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
implementation 'com.squareup.okhttp3:logging-interceptor:3.12.1'

RetrofitClient

HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);

OkHttpClient client = new OkHttpClient.Builder()
        .addInterceptor(logging)
        .build();

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

È anche possibile verificare i risultati andando nella scheda Profiler nella parte inferiore di Android Studio, quindi facendo clic su + segno per avviare una nuova sessione, quindi selezionare il picco desiderato in "Rete". Lì puoi ottenere tutto, ma è ingombrante e lento. Si prega di vedere l'immagine qui sotto.

inserisci qui la descrizione dell'immagine


1

Un modo migliore per eseguire questa operazione in Retrofit 2 è aggiungere l'intercettore del logger come networkInterceptor che stamperà le intestazioni di rete e anche le intestazioni personalizzate. L'importante è ricordare che l'interceptor funziona come uno stack e assicurarsi di aggiungere il logger alla fine di tutto.

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

1

La maggior parte della risposta qui copre quasi tutto tranne questo strumento, uno dei modi più interessanti per visualizzare il registro.

È lo Stetho di Facebook . Questo è lo strumento eccezionale per monitorare / registrare il traffico di rete della tua app su Google Chrome . Puoi anche trovare qui su Github.

inserisci qui la descrizione dell'immagine


1

per Retrofit 2.0.2 il codice è simile

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

1

Ecco un modo semplice per filtrare qualsiasi parametro di richiesta / risposta dai registri usando HttpLoggingInterceptor:

// Request patterns to filter
private static final String[] REQUEST_PATTERNS = {
    "Content-Type",
};
// Response patterns to filter
private static final String[] RESPONSE_PATTERNS = {"Server", "server", "X-Powered-By", "Set-Cookie", "Expires", "Cache-Control", "Pragma", "Content-Length", "access-control-allow-origin"};

// Log requests and response
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
    @Override
    public void log(String message) {

        // Blacklist the elements not required
        for (String pattern: REQUEST_PATTERNS) {
            if (message.startsWith(pattern)) {
                return;
            }
        }
        // Any response patterns as well...
        for (String pattern: RESPONSE_PATTERNS) {
            if (message.startsWith(pattern)) {
                return;
            }
        }
        Log.d("RETROFIT", message);
    }
});
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);

Ecco l'essenza completa:

https://gist.github.com/mankum93/179c2d5378f27e95742c3f2434de7168


1

Ero anche bloccato in un simile tipo di situazione, il setLevel()metodo non stava arrivando, quando stavo cercando di chiamarlo con l'istanza di HttpLoggingInterceptor, in questo modo:

HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);

Ecco come l'ho risolto, per generare il registro per Retrofit2,

Suppongo che tu abbia aggiunto la dipendenza,

implementation "com.squareup.okhttp3:logging-interceptor:4.7.2"

Per l'ultima versione puoi consultare questo link:

https://github.com/square/okhttp/tree/master/okhttp-logging-interceptor )

Qui hanno anche spiegato come aggiungere.

Ho creato una classe con nome AddLoggingInterceptor, ecco il mio codice,

public class AddLoggingInterceptor {

    public static OkHttpClient setLogging(){
        HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
        loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);

        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .addInterceptor(loggingInterceptor)
                .build();

        return okHttpClient;
    }
}

Quindi, dove stiamo istanziando il nostro Retrofit,

 public static Retrofit getRetrofitInstance() {
    if (retrofit == null) {
        retrofit = new retrofit2.Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .client(AddLoggingInterceptor.setLogging()) // here the method is called inside client() method, with the name of class, since it is a static method.
                .build();
    }
    return retrofit;
}

Ora puoi vedere il registro generato nel tuo Android Studio, potrebbe essere necessario cercare il okHttpprocesso di filtraggio. Ha funzionato per me. Se hai problemi puoi scrivermi qui.


0

Ho trovato il modo per Print Log in Retrofit

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

Per me va bene.


0

L'interceptor di Retrofit è un'ottima funzionalità che ti consente di lavorare con le richieste http. Esistono due tipi di questi: intercettori di applicazioni e di rete.

Consiglierei di utilizzare Charles Web Debugging Proxy Applicationse hai bisogno di registrare le tue richieste / risposte. L'output è molto simile a Stetho ma è uno strumento più potente che non è necessario aggiungere come dipendenza a un'applicazione


-11

ciao ragazzi , trovo già la soluzione:

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

Il callback di setLog può inserire ogni registro
Vihuela Yao,

1
questo utilizza retrofit v1, non v2
Gabor,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.