美文网首页程序员
Retrofit使用详解(五)添加日志拦截器

Retrofit使用详解(五)添加日志拦截器

作者: sakasa | 来源:发表于2017-02-16 09:24 被阅读3275次

输出请求日志和响应日志

Retrofit在网络层完全依赖于OkHttp,有人为它做了一个日志拦截器来输出日志,首先在gradle中添加依赖:

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

为OkHttp添加拦截器

HttpLoggingInterceptor logging = new HttpLoggingInterceptor();  
// set your desired log level
logging.setLevel(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();

推荐把输出日志的拦截器放在其他拦截器的后面,这样就会打印出所有的内容。

Log Levels

OkHttp的日志输出有四个级别:

  • NONE
  • BASIC
  • HEADERS
  • BODY

None

没有日志输出。

Basic

日志会输出请求类型(request type),请求地址(url),请求大小(size of request body),响应码(response status)响应大小(size of response body)。

D/HttpLoggingInterceptor$Logger: --> POST /upload HTTP/1.1 (277-byte body)  
D/HttpLoggingInterceptor$Logger: <-- HTTP/1.1 200 OK (543ms, -1-byte body)  

Headers

输出请求和响应的头信息(headers),请求类型(request type),请求地址(request url),响应码(response status)。

使用HEADERS日志级别只会记录请求和响应的头信息。Retrofit或OkHttp会默认添加相应的请求头,但它们不会显示在您的请求上,因为它们稍后会添加到请求链中。 如果自己添加请求头,请确保日志拦截器是添加到OkHttp客户端的最后一个拦截器。 如果您第一个添加拦截器,请求上尚未设置任何头数据。

我们使用两个头字段Accept和Content-Type来说明输出:

D/HttpLoggingInterceptor$Logger: --> POST /upload HTTP/1.1  
D/HttpLoggingInterceptor$Logger: Accept: application/json  
D/HttpLoggingInterceptor$Logger: Content-Type: application/json  
D/HttpLoggingInterceptor$Logger: --> END POST  
D/HttpLoggingInterceptor$Logger: <-- HTTP/1.1 200 OK (1039ms)  
D/HttpLoggingInterceptor$Logger: content-type: text/html; charset=utf-8  
D/HttpLoggingInterceptor$Logger: cache-control: no-cache  
D/HttpLoggingInterceptor$Logger: vary: accept-encoding  
D/HttpLoggingInterceptor$Logger: Date: Wed, 28 Oct 2015 08:24:20 GMT  
D/HttpLoggingInterceptor$Logger: Connection: keep-alive  
D/HttpLoggingInterceptor$Logger: Transfer-Encoding: chunked  
D/HttpLoggingInterceptor$Logger: OkHttp-Selected-Protocol: http/1.1  
D/HttpLoggingInterceptor$Logger: OkHttp-Sent-Millis: 1446020610352  
D/HttpLoggingInterceptor$Logger: OkHttp-Received-Millis: 1446020610369  
D/HttpLoggingInterceptor$Logger: <-- END HTTP  

除了服务器响应的头信息,还会输出选择协议的信息以及发送请求和接收响应时的相应毫秒数。

Body

输出请求和响应的头信息(headers)和内容(body)。

这是您将获得响应正文数据的唯一日志级别。 仅在必要时使用此级别。

D/HttpLoggingInterceptor$Logger: --> POST /upload HTTP/1.1  
D/HttpLoggingInterceptor$Logger: --9df820bb-bc7e-4a93-bb67-5f28f4140795  
D/HttpLoggingInterceptor$Logger: Content-Disposition: form-data; name="description"  
D/HttpLoggingInterceptor$Logger: Content-Transfer-Encoding: binary  
D/HttpLoggingInterceptor$Logger: Content-Type: application/json; charset=UTF-8  
D/HttpLoggingInterceptor$Logger: Content-Length: 37  
D/HttpLoggingInterceptor$Logger:  
D/HttpLoggingInterceptor$Logger: "hello, this is description speaking"  
D/HttpLoggingInterceptor$Logger: --9df820bb-bc7e-4a93-bb67-5f28f4140795--  
D/HttpLoggingInterceptor$Logger: --> END POST (277-byte body)  
D/HttpLoggingInterceptor$Logger: <-- HTTP/1.1 200 OK (1099ms)  
D/HttpLoggingInterceptor$Logger: content-type: text/html; charset=utf-8  
D/HttpLoggingInterceptor$Logger: cache-control: no-cache  
D/HttpLoggingInterceptor$Logger: vary: accept-encoding  
D/HttpLoggingInterceptor$Logger: Date: Wed, 28 Oct 2015 08:33:40 GMT  
D/HttpLoggingInterceptor$Logger: Connection: keep-alive  
D/HttpLoggingInterceptor$Logger: Transfer-Encoding: chunked  
D/HttpLoggingInterceptor$Logger: OkHttp-Selected-Protocol: http/1.1  
D/HttpLoggingInterceptor$Logger: OkHttp-Sent-Millis: 1446021170095  
D/HttpLoggingInterceptor$Logger: OkHttp-Received-Millis: 1446021170107  
D/HttpLoggingInterceptor$Logger: Perfect!  
D/HttpLoggingInterceptor$Logger: <-- END HTTP (8-byte body)  

只在开发环境下输出日志

自动化是增强开发人员关注点和生产力的最佳工具之一。启用和禁用Retrofit的日志记录可能是一个繁琐,重复的任务。所以让我们自动化这个过程:在开发过程中,将为调试版本启用日志记录; 并且您的应用程序的所有生产版本的日志记录将被禁用!

解决方案很简单:我们将使用由Android框架提供的BuildConfig.DEBUG布尔变量。 它将为您的开发环境返回true,对于您的生产环境返回false。

OkHttpClient.Builder httpClient = new OkHttpClient.Builder();

if (BuildConfig.DEBUG) {  
    HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
    logging.setLevel(Level.BODY);

    httpClient.addInterceptor(logging);
}

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

使用不同级别的日志

OkHttpClient.Builder httpClient = new OkHttpClient.Builder();

HttpLoggingInterceptor logging = new HttpLoggingInterceptor();

if (BuildConfig.DEBUG) {  
    // development build
    logging.setLevel(Level.BODY);
} else {
    // production build
    logging.setLevel(Level.BASIC);
}

httpClient.addInterceptor(logging);

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

这样就可以在生产环境和正式环境中输出不同的日志了。

捕捉错误

在服务器发生错误或者用户输入的数据错误时,我们希望呈献给用户反馈信息,并要求他改正。

在这之前,我们来看一个简单的例子:

Error Object

首先我们创建一个错误json:

{
    statusCode: 409,
    message: "Email address already registered"
}

定义一个错误类

public class APIError {

    private int statusCode;
    private String message;

    public APIError() {
    }

    public int status() {
        return statusCode;
    }

    public String message() {
        return message;
    }
}

Simple Error Handler

我们将使用下面的类,返回一个APIError对象的静态方法。 parseError方法的参数为Response。 此外,您需要使您的Retrofit实例可用,以便为接收到的JSON错误响应应用适当的响应转换器。

public class ErrorUtils {

    public static APIError parseError(Response<?> response) {
        Converter<ResponseBody, APIError> converter = 
                ServiceGenerator.retrofit()
                        .responseBodyConverter(APIError.class, new Annotation[0]);

        APIError error;

        try {
            error = converter.convert(response.errorBody());
        } catch (IOException e) {
            return new APIError();
        }

        return error;
    }
}

首先将APIError类作为参数传递给responseBodyConverter方法,这个方法是retrofit中的方法。responseConverter方法将返回适当的转换器来解析响应体类型。

Error Handler inAction

在Retrofit 2中,所有可以执行(发送到API)并且接收到响应的请求都被视为“sucess”。这意味着,对于这些请求,onResponse回调被触发,您需要手动检查请求是否实际成功(状态200-299)或错误(状态400-599)。

如果请求成功完成,我们可以使用响应对象,并做任何我们想要的。 如果错误实际上失败(状态400-599),我们要向用户显示有关该问题的适当信息。

Call<User> call = service.me();  
call.enqueue(new Callback<User>() {  
    @Override
    public void onResponse(Call<User> call, Response<User> response) {
        if (response.isSuccessful()) {
            // use response data and do some fancy stuff :)
        } else {
            // parse the response body …
            APIError error = ErrorUtils.parseError(response);
            // … and use it to show error information

            // … or just log the issue like we’re doing :)
            Log.d("error message", error.message());
        }
    }

    @Override
    public void onFailure(Call<User> call, Throwable t) {
        // there is more than just a failing request (like: no internet connection)
    }
});

这样就可以使用ErrorUtils类来处理错误了。

相关文章

网友评论

    本文标题:Retrofit使用详解(五)添加日志拦截器

    本文链接:https://www.haomeiwen.com/subject/aomcwttx.html