จะบันทึกคำขอและเนื้อหาตอบกลับด้วย Retrofit-Android ได้อย่างไร


129

ฉันไม่พบวิธีการที่เกี่ยวข้องใน Retrofit API สำหรับการบันทึกเนื้อหาคำขอ / การตอบกลับที่สมบูรณ์ ฉันคาดหวังความช่วยเหลือบางอย่างใน Profiler (แต่มีเฉพาะข้อมูลเมตาเกี่ยวกับการตอบสนองเท่านั้น) ฉันพยายามตั้งค่าระดับการบันทึกใน Builder แต่ก็ไม่ได้ช่วยฉันเช่นกัน:

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

แก้ไข: รหัสนี้ใช้งานได้แล้ว ฉันไม่รู้ว่าทำไมมันถึงไม่ทำงานก่อนหน้านี้ อาจเป็นเพราะฉันใช้ชุดติดตั้งรุ่นเก่าบางรุ่น


คุณเคยคิดออกไหม? เอกสารระบุว่าFULLควรจะให้ร่างกาย แต่ดูเหมือนจะไม่
theblang

1
@mattblang: ฉันไม่รู้ว่าก่อนหน้านี้มีอะไรผิดพลาด แต่รหัสนี้ใช้งานได้แล้ว
จากัวร์



อาจจะทำให้การเรียกใช้ทันทีสับสนหากไม่ได้ผลก่อนหน้านี้
deathangel908

คำตอบ:


91

ฉันใช้setLogLevel(LogLevel.FULL).setLog(new AndroidLog("YOUR_LOG_TAG"))มันช่วยฉัน
UPDATE
คุณยังสามารถลองใช้วัตถุประสงค์ในการดีบักretrofit.client.Responseเป็นรูปแบบการตอบสนอง


2
AndroidLog, ชั้นคืออะไร?
theblang

มาพร้อมกับ Retrofit library
Alex Dzeshko

2
ฉันเห็น. น่าเสียดายที่สิ่งนี้ไม่ได้ให้ข้อมูลแก่คุณresponse bodyแม้ว่าจะระบุไว้ในเอกสารที่LogLevel.FULL ควรให้ไฟล์response body.
theblang

สิ่งนี้สามารถเห็นได้ด้วย "YOUR_LOG_TAG" ใน android logcat ใต้แท็บ verbose
rajeesh

4
LogLevel.Full ไม่มีอยู่ในชุดติดตั้งเพิ่ม 2

121

ชุดติดตั้งเพิ่ม 2.0 :

UPDATE: @ โดย Marcus Pöhls

การเข้าสู่ระบบชุดติดตั้งเพิ่มเติม 2

Retrofit 2 ใช้ OkHttp สำหรับการทำงานของเครือข่ายใด ๆ เนื่องจาก OkHttp เป็นการพึ่งพาแบบเพียร์ของ Retrofit 2 คุณจึงไม่จำเป็นต้องเพิ่มการพึ่งพาเพิ่มเติมเมื่อ Retrofit 2 ถูกปล่อยออกมาเป็นรุ่นที่เสถียร

OkHttp 2.6.0 มาพร้อมกับเครื่องสกัดกั้นการบันทึกเป็นการพึ่งพาภายในและคุณสามารถใช้กับไคลเอ็นต์ Retrofit ของคุณได้โดยตรง Retrofit 2.0.0-beta2 ยังคงใช้ OkHttp 2.5.0 การเปิดตัวในอนาคตจะส่งผลต่อการอ้างอิงไปยังเวอร์ชัน OkHttp ที่สูงขึ้น นั่นเป็นเหตุผลที่คุณต้องนำเข้าเครื่องสกัดกั้นการบันทึกด้วยตนเอง เพิ่มบรรทัดต่อไปนี้ในการนำเข้า gradle ของคุณภายในไฟล์ build.gradle ของคุณเพื่อดึงการพึ่งพาตัวสกัดกั้นการบันทึก

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

คุณยังสามารถไปที่หน้า GitHub ของ Square เกี่ยวกับตัวสกัดกั้นนี้

เพิ่มการบันทึกลงในชุดติดตั้งเพิ่ม 2

ในขณะที่พัฒนาแอปของคุณและเพื่อวัตถุประสงค์ในการดีบักเป็นเรื่องดีที่มีคุณลักษณะบันทึกที่รวมเข้าด้วยกันเพื่อแสดงข้อมูลคำขอและการตอบกลับ เนื่องจากการบันทึกไม่ได้รวมเข้ากับค่าเริ่มต้นอีกต่อไปในชุดติดตั้งเพิ่ม 2 เราจึงจำเป็นต้องเพิ่มตัวสกัดกั้นการบันทึกสำหรับ OkHttp โชคดีที่ OkHttp มาพร้อมกับเครื่องสกัดกั้นนี้แล้วและคุณจะต้องเปิดใช้งานสำหรับ 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();

เราขอแนะนำให้เพิ่มการบันทึกเป็นตัวสกัดกั้นสุดท้ายเนื่องจากจะบันทึกข้อมูลที่คุณเพิ่มไว้กับตัวดักจับก่อนหน้าในคำขอของคุณด้วย

ระดับการบันทึก

การบันทึกข้อมูลมากเกินไปจะทำให้หน้าจอ Android ของคุณระเบิดนั่นคือสาเหตุที่เครื่องดักฟังการบันทึกของ OkHttp มีระดับการบันทึกสี่ระดับ: ไม่มี, พื้นฐาน, ส่วนหัว, ร่างกาย เราจะแนะนำคุณเกี่ยวกับระดับการบันทึกแต่ละระดับและอธิบายผลลัพธ์

ข้อมูลเพิ่มเติมกรุณาเยี่ยมชม: ชุดติดตั้งเพิ่ม 2 - คำขอบันทึกและการตอบกลับ

คำตอบเก่า:

ไม่มีการเข้าสู่ระบบ Retrofit 2 อีกต่อไป ทีมพัฒนาได้ลบคุณลักษณะการบันทึก ตามจริงแล้วคุณสมบัติการบันทึกก็ไม่น่าเชื่อถืออยู่ดี Jake Wharton ระบุอย่างชัดเจนว่าข้อความหรือวัตถุที่บันทึกไว้เป็นค่าที่สันนิษฐานและไม่สามารถพิสูจน์ได้ว่าเป็นจริง คำขอจริงที่มาถึงเซิร์ฟเวอร์อาจมีเนื้อหาคำขอที่เปลี่ยนแปลงหรืออย่างอื่น

แม้ว่าจะไม่มีการบันทึกแบบรวมตามค่าเริ่มต้น แต่คุณสามารถใช้ประโยชน์จาก Java logger ใด ๆ และใช้ภายในตัวสกัดกั้น OkHttp ที่กำหนดเองได้

ข้อมูลเพิ่มเติมเกี่ยวกับ Retrofit 2 โปรดดู: ชุดติดตั้งเพิ่ม - เริ่มต้นใช้งานและสร้างไคลเอนต์ Android


1
นอกจากนี้ยังมีโพสต์เฉพาะสำหรับการเข้าสู่ระบบใน Retrofit 2.0: futurestud.io/blog/retrofit-2-log-requests-and-responses
peitek

วิธีที่ยอดเยี่ยมในการทำให้ทุกอย่างซับซ้อนกว่าที่ควรจะเป็น ทำให้ฉันนึกถึงการบันทึก Jersey 1 vs Jersey 2 รหัสสำเร็จรูปอื่น ๆ ....
breakline

การเพิ่มตัวดักจับด้วยวิธีนี้จะทำให้เกิด UnsupportedOperationException ใน OkHttp v3 วิธีใหม่คือ OkHttpClient.Builder (). addInterceptor (logging) .build () github.com/square/okhttp/issues/2219
Amagi82

@JawadLeWywadi ใช่โดยใช้รหัสนี้คุณสามารถพิมพ์เนื้อความได้
Dhaval Jivani

สำหรับการติดตั้งเพิ่มที่ 2 นี้เป็นเรื่องง่ายมาก
Gary99

31

อัปเดตสำหรับ Retrofit 2.0.0-beta3

ตอนนี้คุณต้องใช้ okhttp3 กับ builder นอกจากนี้ตัวสกัดกั้นเก่าจะไม่ทำงาน คำตอบนี้ได้รับการปรับแต่งสำหรับ Android

นี่คือสำเนาด่วนสำหรับคุณพร้อมกับสิ่งใหม่ ๆ

1. แก้ไขไฟล์ gradle ของคุณเป็น

  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. ตรวจสอบโค้ดตัวอย่างนี้:

ด้วยการนำเข้าใหม่ คุณสามารถลบ Rx ได้ถ้าคุณไม่ใช้มันและลบสิ่งที่คุณไม่ได้ใช้ด้วย

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

โบนัส

ฉันรู้ว่ามันผิดปกติ แต่ฉันคิดว่ามันเจ๋ง

ในกรณีที่มีรหัสข้อผิดพลาด http ที่ไม่ได้รับอนุญาตนี่คือตัวสกัดกั้น ฉันใช้ 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;
  }
}

ใช้รหัสจากhttps://github.com/AndreiD/UltimateAndroidTemplateRx (โครงการของฉัน)


9

ดูเหมือนจะไม่มีวิธีทำ Basic + body แต่คุณสามารถใช้ FULL และกรองส่วนหัวที่คุณไม่ต้องการได้

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

ดูเหมือนว่าเมื่อแทนที่บันทึกเนื้อหาจะถูกนำหน้าด้วยแท็กที่คล้ายกับ

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

ดังนั้นจึงควรง่ายต่อการบันทึกร่างกาย + พื้นฐานโดยการปรับตัวกรองที่กำหนดเอง ฉันกำลังใช้บัญชีดำ แต่สามารถใช้รายการที่อนุญาตพิเศษได้ขึ้นอยู่กับความต้องการของคุณ


4

โค้ดด้านล่างใช้งานได้ทั้งที่มีส่วนหัวและไม่มีส่วนหัวเพื่อพิมพ์คำขอบันทึกและการตอบกลับ หมายเหตุ: เพียงแสดงความคิดเห็นบรรทัด. addHeader () หากไม่ได้ใช้ส่วนหัว

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

ฉันหวังว่ารหัสนี้จะช่วยคุณในการบันทึก
คุณเพียงแค่ต้องเพิ่ม interceptor ในBuild.Gradlemake ของRetrofitClientคุณ

ขั้นแรก

เพิ่มบรรทัดนี้ในไฟล์ build.gradle

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

ขั้นตอนที่สอง

สร้าง Retrofit Client ของคุณ


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

การเรียกร้อง

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

2

หากคุณใช้ Retrofit2 และ okhttp3 คุณจำเป็นต้องรู้ว่า Interceptor ทำงานตามคิว ดังนั้นเพิ่ม loggingInterceptor ในตอนท้ายหลังจาก Interceptors อื่น ๆ ของคุณ:

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


0

สำหรับ android studio ก่อน 3.0 (ใช้ android motinor)
https://futurestud.io/tutorials/retrofit-2-log-requests-and-responses
https://www.youtube.com/watch?v=vazLpzE5y9M

และสำหรับ android studio ตั้งแต่ 3.0 ขึ้นไป (ใช้ android profiler เนื่องจาก android monitor ถูกแทนที่ด้วย android profiler)
https://futurestud.io/tutorials/retrofit-2-analyze-network-traffic-with-android-studio-profiler

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.