1. 程式人生 > >android,retrofit,okhttp,日誌攔截器,使用攔截器Interceptor統一列印請求與響應的json

android,retrofit,okhttp,日誌攔截器,使用攔截器Interceptor統一列印請求與響應的json

   可以打印出傳遞的引數以及返回的結果 :  最下面有完整的 retrofit 案例

------------------retrofit的使用----START--------------------------

首先 : 依賴 :

compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:converter-scalars:2.1.0'
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
1. 攔截器 :
/**
 * Retrofit2 Logger攔截器。
 */
public final class LoggingInterceptor implements Interceptor {
    private static final Charset UTF8 = Charset.forName("UTF-8");

    public enum Level {
        NONE,
        HEADERS,
        BODY
    }

    public interface Logger {
        void log(String message);

        Logger DEFAULT = new Logger() {
            @Override
            public void log(String message) {
                //Platform.get().log(4, message, null);
            }
        };
    }

    public LoggingInterceptor() {
        this(Logger.DEFAULT);
    }

    public LoggingInterceptor(Logger logger) {
        this.logger = logger;
    }

    private final Logger logger;

    private volatile Level level = Level.NONE;

    /**
     * Change the level at which this interceptor logs.
     */
    public LoggingInterceptor setLevel(Level level) {
        if (level == null) throw new NullPointerException("level == null. Use Level.NONE instead.");
        this.level = level;
        return this;
    }

    public Level getLevel() {
        return level;
    }

    @Override
    public Response intercept(Chain chain) throws IOException {
        Level level = this.level;

        Request request = chain.request();
        if (level == Level.NONE) {
            return chain.proceed(request);
        }

        boolean logBody = level == Level.BODY;
        boolean logHeaders = logBody || level == Level.HEADERS;

        RequestBody requestBody = request.body();
        boolean hasRequestBody = requestBody != null;

        Connection connection = chain.connection();
        Protocol protocol = connection != null ? connection.protocol() : Protocol.HTTP_1_1;
        String requestStartMessage =
                "--> " + request.method() + ' ' + request.url() + ' ' + protocol(protocol);
        if (!logHeaders && hasRequestBody) {
            requestStartMessage += " (" + requestBody.contentLength() + "-byte body)";
        }
        logger.log(requestStartMessage);

        if (logHeaders) {
            if (hasRequestBody) {
                // Request body headers are only present when installed as a network interceptor. Force
                // them to be included (when available) so there values are known.
                if (requestBody.contentType() != null) {
                    logger.log("Content-Type: " + requestBody.contentType());
                }
                if (requestBody.contentLength() != -1) {
                    logger.log("Content-Length: " + requestBody.contentLength());
                }
            }

            Headers headers = request.headers();
            for (int i = 0, count = headers.size(); i < count; i++) {
                String name = headers.name(i);
                // Skip headers from the request body as they are explicitly logged above.
                if (!"Content-Type".equalsIgnoreCase(name) && !"Content-Length".equalsIgnoreCase(name)) {
                    logger.log(name + ": " + headers.value(i));
                }
            }

            if (!logBody || !hasRequestBody) {
                logger.log("--> END " + request.method());
            } else if (bodyEncoded(request.headers())) {
                logger.log("--> END " + request.method() + " (encoded body omitted)");
            } else {
                Buffer buffer = new Buffer();
                requestBody.writeTo(buffer);

                Charset charset = UTF8;
                MediaType contentType = requestBody.contentType();
                if (contentType != null) {
                    charset = contentType.charset(UTF8);
                }

                logger.log("");
                logger.log(buffer.readString(charset));

                logger.log(
                        "--> END " + request.method() + " (" + requestBody.contentLength() + "-byte body)");
            }
        }

        long startNs = System.nanoTime();
        Response response = chain.proceed(request);
        long tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs);

        ResponseBody responseBody = response.body();
        long contentLength = responseBody.contentLength();
        String bodySize = contentLength != -1 ? contentLength + "-byte" : "unknown-length";
        logger.log("<-- "
                + response.code()
                + ' '
                + response.message()
                + ' '
                + response.request().url()
                + " ("
                + tookMs
                + "ms"
                + (!logHeaders ? ", " + bodySize + " body" : "")
                + ')');

        if (logHeaders) {
            Headers headers = response.headers();
            for (int i = 0, count = headers.size(); i < count; i++) {
                logger.log(headers.name(i) + ": " + headers.value(i));
            }

            if (!logBody || !HttpEngine.hasBody(response)) {
                logger.log("<-- END HTTP");
            } else if (bodyEncoded(response.headers())) {
                logger.log("<-- END HTTP (encoded body omitted)");
            } else {
                BufferedSource source = responseBody.source();
                source.request(Long.MAX_VALUE); // Buffer the entire body.
                Buffer buffer = source.buffer();

                Charset charset = UTF8;
                MediaType contentType = responseBody.contentType();
                if (contentType != null) {
                    charset = contentType.charset(UTF8);
                }

                if (contentLength != 0) {
                    logger.log("");
                    logger.log(buffer.clone().readString(charset));
                }

                logger.log("<-- END HTTP (" + buffer.size() + "-byte body)");
            }
        }

        return response;
    }

    private boolean bodyEncoded(Headers headers) {
        String contentEncoding = headers.get("Content-Encoding");
        return contentEncoding != null && !contentEncoding.equalsIgnoreCase("identity");
    }

    private static String protocol(Protocol protocol) {
        return protocol == Protocol.HTTP_1_0 ? "HTTP/1.0" : "HTTP/1.1";
    }
}

2. 重寫:

public class Logger implements LoggingInterceptor.Logger {

    @Override
    public void log(String message) {
        LogUtils.i("http : " + message);
    }
}

3. 再次封裝:

LoggingInterceptor logging = new LoggingInterceptor(new Logger());
logging.setLevel(LoggingInterceptor.Level.BODY);

OkHttpClient.Builder builder = new OkHttpClient.Builder().connectTimeout(10, TimeUnit.SECONDS)
        .connectTimeout(5 * 1000, TimeUnit.MILLISECONDS)
        .readTimeout(5 * 1000, TimeUnit.MILLISECONDS)
        .retryOnConnectionFailure(true) // 失敗重發
        .addInterceptor(logging);

Retrofit retrofit = new Retrofit.Builder()
        .baseUrl(Constant.API_BASE_URL)
        .addConverterFactory(GsonConverterFactory.create()) // 新增Gson轉換器
        .client(builder.build())
        .build();

------------以上是對retrofit的使用封裝,在第三個步驟中還要返回自己的代理類 --------END-----------

 下面對 okhttp進行封裝

   首先新增依賴 :

compile 'com.squareup.okhttp3:okhttp:3.9.0'

  解釋 : 這個依賴是 okhttp3,至於和okhttp有什麼不同,請自行百度檢視,在這裡說下我自己的理解 :

         okhttp3可以通過builder的形式,完成對okhttp的建立

第一步 : 對攔截器進行重寫 :   (我從網上找的,應該可以滿足日常使用)

package intercept;
import android.util.Log;
import java.io.IOException;
import java.util.Locale;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;

public class LoggingInterceptor implements Interceptor {
    String TAG = "LoggingInterceptor";

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        Log.v(TAG, "request:" + request.toString());
        long t1 = System.nanoTime();
        okhttp3.Response response = chain.proceed(chain.request());
        long t2 = System.nanoTime();
        Log.v(TAG, String.format(Locale.getDefault(), "Received response for %s in %.1fms%n%s", response.request().url(), (t2 - t1) / 1e6d, response.headers()));
        okhttp3.MediaType mediaType = response.body().contentType();
        String content = response.body().string();
        Log.i(TAG, "response body:" + content);
        return response.newBuilder().body(okhttp3.ResponseBody.create(mediaType, content)).build();
    }  // 下面的span沒什麼用
}

  第二步 :  對 okhttp進行簡單的封裝

package intenet;
import intercept.LoggingInterceptor;
import okhttp3.OkHttpClient;

public class OkhttpUtils {
    static OkHttpClient okHttpClient;
    /**
     *  以builder的形式構建 okhttp,如果只是通過new的形式,建立不了攔截器
     * @return
     */
    public static OkHttpClient getOkhttpInstance() {

        if (okHttpClient == null) {
            synchronized (OkhttpUtils.class) {   // 雙重加鎖機制,後面也要對空判斷,假設兩個執行緒都到這裡,不判斷,下一個執行緒還是會再建立
                if (okHttpClient == null) {
                    okHttpClient = new OkHttpClient.Builder()
                            .addInterceptor(new LoggingInterceptor())
                            .build();
                }
            }
        }
        return okHttpClient;
    }
}

第三步 :   網路請求, url裡面有 easy-mock, 這是一個可以自己造假資料的網站,可以學習一下

final String url = "https://easy-mock.com/mock/59dc1fbe1de3d46fa94c74c6/ceshi/example";
new Thread() {
    @Override
    public void run() {
        super.run();
        OkHttpClient okhttpClient = OkhttpUtils.getOkhttpInstance();  // 通過builder構建 okhttp
        Request request = new Request.Builder().get().url(url).build();
        okhttp3.Call call = okhttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Toast.makeText(getActivity(), "網路請求失敗", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String result = response.body().string();
              //  Log.e("result 網路請求結果是 :::", "onResponse: " + result);
                Gson gson = new Gson();
                TestBan bean = gson.fromJson(result, TestBan.class);
                TestBan.DateBean dataBean = bean.date;
                final String dataTime = dataBean.datetime;
                getActivity().runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(getActivity(), "第二個介面請求成功", Toast.LENGTH_SHORT).show();
                    }
                });
            }
        });

注意 :  

     選擇 ----> NO Filters

    完結 : 可以在控制檯打印出 json 資料.

下面是我自己用 retrofit 配合 okhttp來列印請求以及返回資料的完整案例,okhttp可以用來 :

  http://blog.csdn.net/qq_37043246/article/details/79075479     (自行檢視)

步驟  :

①  依賴

implementation 'com.squareup.retrofit2:retrofit:2.1.0'
implementation 'com.squareup.retrofit2:converter-gson:2.1.0'
implementation 'com.squareup.okhttp3:logging-interceptor:3.4.1

②  封裝 :

package api;
import java.util.concurrent.TimeUnit;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Call;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public class ApiServiceFactory {
    private Api mApi;
    private static ApiServiceFactory mFactory;
    private ApiServiceFactory() {   // 私有主要讓它使用  getInstance 來 創建出 factory
        HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
        httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);

        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        builder.connectTimeout(5 * 1000, TimeUnit.MILLISECONDS)
                .readTimeout(5 * 1000, TimeUnit.MILLISECONDS)
                .retryOnConnectionFailure(true) // 失敗重發
                .addInterceptor(httpLoggingInterceptor);

        Retrofit retrofit = new Retrofit.Builder()
                //使用自定義的mGsonConverterFactory
                .addConverterFactory(GsonConverterFactory.create())
                .baseUrl("https://easy-mock.com/mock/59dc1fbe1de3d46fa94c74c6/ceshi/")
                .client(builder.build())
                .build();
        mApi = retrofit.create(Api.class);
    }

    public static ApiServiceFactory getInstance() {
        if (mFactory == null) {
            mFactory = new ApiServiceFactory();
        }
        return mFactory;
    }

    public Call<String> queryList(String name) {
        return mApi.queryList(name);
    }
}

③ 介面 :

package api;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Query;
public interface Api {
    @GET("example")
    Call<String> queryList(@Query("name") String name);
}
④  介面 :
package t.cn.myowntest;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.Toast;
import api.ApiServiceFactory;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

public class Main3Activity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main3);
        getData();
    }

    private void getData() {
        Call<String> call = ApiServiceFactory.getInstance().queryList("winner");
        call.enqueue(new Callback<String>() {
            @Override
            public void onResponse(Call<String> call, Response<String> response) {
            }
            @Override
            public void onFailure(Call<String> call, Throwable t) {
                Toast.makeText(Main3Activity.this, "失敗了", Toast.LENGTH_SHORT).show();
            }
        });
    }
}

⑤ 列印 :