如何记录请求和响应主体与改造-Android?

我找不到用于记录完整的请求/响应主体的 Requfit 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();

编辑: 这个代码现在正在工作。我不知道为什么之前没用。可能是因为我用的是旧版改装。

163783 次浏览

我用 setLogLevel(LogLevel.FULL).setLog(new AndroidLog("YOUR_LOG_TAG")),它帮助我。
您还可以尝试使用 retrofit.client.Response作为响应模型进行调试

似乎没有一种方法来做基本 + 体,但你可以使用 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 ]

所以通过调整自定义过滤器,很容易记录 basic + body。我正在使用黑名单,但白名单也可以根据您的需要使用。

改造2.0版本 :

更新:@by Marcus Pöhls

在改造中登录2

所有的网络操作都完全依赖于 OkHttp。由于 OkHttp 是便携式恢复2的对等依赖项,一旦便携式恢复2作为稳定版发布,您就不需要添加额外的依赖项。

OkHttp 2.6.0附带了一个日志拦截器作为内部依赖项,您可以直接将其用于便携式客户端。付费版2.0.0-beta2仍然使用 OkHttp 2.5.0。未来的版本将把依赖性提升到更高的 OkHttp 版本。这就是为什么需要手动导入日志拦截器。将以下代码行添加到 build.gradle 文件中的 gradle 导入中,以获取日志拦截器依赖项。

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

您还可以访问 Square 的 GitHub 页面,了解这个拦截器

将日志添加到改造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 的日志拦截器有四个日志级别: NONE,BASIC,HEADERS,BODY。我们将带您遍历每个日志级别并描述它们的输出。

详情请浏览: 翻新2-日志请求和响应

老答案:

不能再在“改造2”中进行日志记录了。开发团队删除了日志特性。老实说,日志记录功能并不是那么可靠。Jake Wharton 明确表示,记录的消息或对象是假定的值,它们不能被证明是真实的。到达服务器的实际请求可能具有已更改的请求主体或其他内容。

即使缺省情况下没有集成日志记录,您也可以利用任何 Java 日志记录器并在定制的 OkHttp 拦截器中使用它。

有关加装2的进一步资料,请参阅: 改造ーー启动并创建 Android 客户端

更新改造2.0.0-beta 3

现在,您必须在 Builder 中使用 okhttp3。而且旧的拦截器也不能工作。这个响应是为 Android 量身定做的。

这里有一个快速复制粘贴与新的东西给你。

1. 将你的等级文件修改为

  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 错误代码,这里有一个拦截器。

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(我的项目)的代码。

如果您正在使用 Requfit2和 okhttp3,那么您需要知道 Interceptor 是按队列工作的。因此,在其他拦截器之后,在最后添加 loggingInterceptor:

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

下面的代码可以同时打印带头和不带头的日志请求和响应

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.0之前为安卓工作室(使用安卓马达)
Https://futurestud.io/tutorials/retrofit-2-log-requests-and-responses
Https://www.youtube.com/watch?v=vazlpze5y9m

对于3.0及以上版本的 android 工作室(使用 android 分析器作为 android 监视器被 android 分析器取代)
Https://futurestud.io/tutorials/retrofit-2-analyze-network-traffic-with-android-studio-profiler

我希望这段代码可以帮助您进行日志记录。
你只需要在你的 Build.Gradle中加入拦截器,然后使 RetrofitClient

第一步

将这一行添加到 build.gradle

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

第二步

让你的翻新客户


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


ZoomX ー Android 日志拦截器 是一个很好的拦截器,可以帮助您解决问题。

call.request().toString();

发送到服务器的屏幕截图请求: enter image description here

这是 不是最好的办法,更好的答案在上面。这只是使用 Android 日志检查它的另一种方法。将它们全部放在这里有助于捕获解析错误。

 call.enqueue(new Callback<JsonObject>() {
@Override
public void onResponse(Call<JsonObject> call,
Response<JsonObject> response) {


// Catching Responses From Retrofit
Log.d("TAG", "onResponseisSuccessful: "+response.isSuccessful());
Log.d("TAG", "onResponsebody: "+response.body());
Log.d("TAG", "onResponseerrorBody: "+response.errorBody());
Log.d("TAG", "onResponsemessage: "+response.message());
Log.d("TAG", "onResponsecode: "+response.code());
Log.d("TAG", "onResponseheaders: "+response.headers());
Log.d("TAG", "onResponseraw: "+response.raw());
Log.d("TAG", "onResponsetoString: "+response.toString());


}


@Override
public void onFailure(Call<JsonObject> call,
Throwable t) {


Log.d("TAG", "onFailuregetLocalizedMessage: " +t.getLocalizedMessage());
Log.d("TAG", "onFailuregetMessage: " +t.getMessage());
Log.d("TAG", "onFailuretoString: " +t.toString());
Log.d("TAG", "onFailurefillInStackTrace: " +t.fillInStackTrace());
Log.d("TAG", "onFailuregetCause: " +t.getCause());
Log.d("TAG", "onFailuregetStackTrace: " + Arrays.toString(t.getStackTrace()));
Log.d("TAG", "getSuppressed: " + Arrays.toString(t.getSuppressed()));


}
});

请在 okHttpClient 中添加拦截器,以便在改造 Android 中调用 API 时获得请求和响应日志

 private static final OkHttpClient okHttpClient = new OkHttpClient.Builder()
.readTimeout(180, TimeUnit.SECONDS)
.writeTimeout(180, TimeUnit.SECONDS)
.connectTimeout(180, TimeUnit.SECONDS)
.addInterceptor(getLoggin())
.build();








public static HttpLoggingInterceptor getLoggin(){
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
return logging;
}

理想情况下,如果使用 木材,效果会更好,因为您还可以对应用程序中的日志消息进行全局处理,比如将它们保存到文件中。 下面是如何让 Httplogging 拦截器与木材一起工作:

val loggingInterceptor = HttpLoggingInterceptor { message ->
Timber.d(message)
}.apply {
level = HttpLoggingInterceptor.Level.BODY
}


val client = OkHttpClient.Builder()
.addInterceptor(loggingInterceptor)
.build()


return Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build()
.create(RetrofitApiService::class.java)

您还可以通过这种方式创建您自己的日志截取程序实现:

class HttpLoggingInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request: Request = chain.request()


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


val response = chain.proceed(request)


val responseBody: ResponseBody? = response.body
val responseBodyString = response.body!!.string()


val newResponse = response.newBuilder()
.body(responseBodyString.toResponseBody(responseBody?.contentType()))
.build()


val t2 = System.nanoTime()
Timber.i(
"Received response for %s in %.1fms%n%s",
response.request.url,
(t2 - t1) / 1e6,
response.headers
)
Timber.v("RESPONSE BODY BEGIN:\n%s\nRESPONSE BODY END", responseBodyString)


return newResponse
}


private fun bodyToString(request: Request): String? {
return try {
val copy = request.newBuilder().build()
val buffer = Buffer()
copy.body!!.writeTo(buffer)
buffer.readUtf8()
} catch (e: Exception) {
"did not work"
}
}
}

以下是如何添加木材:

implementation "com.jakewharton.timber:timber:5.0.1"