I'm using Retrofit library version 2 with OkHttpClient.
I want to get some header from all responses.
I found one solution with OkClient:
public class InterceptingOkClient extends OkClient{
public InterceptingOkClient()
{
}
public InterceptingOkClient(OkHttpClient client)
{
super(client);
}
#Override
public Response execute(Request request) throws IOException
{
Response response = super.execute(request);
for (Header header : response.getHeaders())
{
// do something with header
}
return response;
}
}
But how i can do this if i'm using OkHttpClient?
Yes, this is old question.. but still found to answer because myself too was searching similar one.
okHttpClient.interceptors().add(new Interceptor() {
#Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request original = chain.request();
// Request customization: add request headers
Request.Builder requestBuilder = original.newBuilder()
.header("Authorization", "auth-value"); // <-- this is the important line, to add new header - replaces value with same header name.
Request request = requestBuilder.build();
Response response = chain.proceed(request);
Headers allHeaders = response.headers();
String headerValue = allHeaders.get("headerName");
return response;
}
});
Hope, this helps!
P.S: no error handled.
You can use the logging interceptor for that. Add it as an interceptor to your OkHttpClient builder while building the client, set the log level and voila! You will have all the information regarding the request as well as the response.
Here's how you can add the interceptor -
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
okHttpBuilder.addInterceptor(loggingInterceptor);
client = okHttpBuilder.build();
There are four options when it comes to what you want to Log - NONE,BASIC,HEADERS, and BODY.
Now build the the retrofit instance with the above defined client and you will have all the data you need.
Related
I saw this question asked so many times but mine is with different case. Please dont mark it as duplicate.
Following is my client for retrofit. Which works perfectly fine when we're using apk. But as soon as we convert it to MDX for citrix/secure hub we are facing this end of stream error.
I have also tried this with volley but am getting same error. As you can see that I have tried all the interceptor and all for retrofit.
Already tried following interceptor.
addHeader("Connection", "close")
retryOnConnectionFailure(true)
So my question is what is happening exactly? Why is it working in apk and not on MDX.
public static Retrofit getClient() {
//Basic Auth
String authToken = null;
if (!TextUtils.isEmpty(AppConfig.username) &&
!TextUtils.isEmpty(AppConfig.password)) {
authToken = Credentials.basic((String) AppConfig.username, (String) AppConfig.password);
}
//Create a new Interceptor.
final String finalAuthToken = authToken;
Interceptor headerAuthorizationInterceptor = new Interceptor() {
#Override
public okhttp3.Response intercept(Chain chain) throws IOException {
okhttp3.Request request = chain.request();
Headers headers = request.headers().newBuilder()
// .add("Authorization", finalAuthToken)
.add("Connection", "close").build();
request = request.newBuilder().headers(headers).build();
return chain.proceed(request);
}
};
//TO be added in milliseconds
List < Protocol > protos = new ArrayList < > ();
protos.add(Protocol.HTTP_2);
protos.add(Protocol.HTTP_1_1);
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(interceptor)
.protocols(protos)
.retryOnConnectionFailure(true) //FIRST TRY : Added this line after getting Unexpected end of stream error.
.connectTimeout(180, TimeUnit.SECONDS)
.readTimeout(180, TimeUnit.SECONDS)
.writeTimeout(180, TimeUnit.SECONDS)
//.addInterceptor(new GzipRequestInterceptor())
// THIRD TRY : Added this new interceptor for end of stream error
/*.addInterceptor(new Interceptor() {
#NonNull
#Override
public Response intercept(#NonNull Chain chain) throws IOException {
Request request = chain.request().newBuilder()
.addHeader("Connection", "close")
.addHeader("Transfer-Encoding", "chunked")
//.addHeader("Accept-Encoding", "gzip")
.build();
return chain.proceed(request);
}
})*/
//.addInterceptor(headerAuthorizationInterceptor) // SECOND TRY : Added this line after getting Unexpected end of stream error. fot connection close
//ABOVE LINE is Next try would be adding this line as
// this headerInterceptor we have added .add("Connection","close")
// may be we need to remove the authorization from that headerInterceptor
.build();
return new Retrofit.Builder()
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.baseUrl(AppConfig.mainURLDev3forRetrofit2)
.build(); }
How can we intercept java.net.HttpURLConnection network requests? However, we can achieve interception using OKHTTPClient. Please help.
If you want to modify request/response with OkHttpClient you can use interceptors. For example If you want to add a header to all requests, you can use the code below. Modifying other parts like body is similar.
OkHttpClient okHttpClient = new OkHttpClient().newBuilder().addInterceptor(new Interceptor() {
#Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();
Request.Builder builder = originalRequest.newBuilder().header("Authorization",
Credentials.basic("aUsername", "aPassword"));
Request newRequest = builder.build();
return chain.proceed(newRequest);
}
}).build();
I need to build a traffic monitor on my Android app, and I need to have stored the size of all json that I'm sending and receiving through retrofit. Using log I can see the actual size of it, but I haven't find a way to get this information so I could save it. I can't get the response.raw either since it's already been parsed to my classes. Is there any way to achieve that?
EDIT: Marked vadkou answer as the best one.
Instead of creating a new interceptor, I passed the lamda expression:
httpClient.addInterceptor( chain -> {
okhttp3.Request request = chain.request();
okhttp3.Response response = chain.proceed(request);
if(request.body()!=null) {
long requestLength = request.body().contentLength();
Log.e("SERVICE GENERATOR", " CONTENT LENGTH" + requestLength);
}
long responseLength = response.body().contentLength();
Log.e("SERVICE GENERATOR", " RESPONSE LENGTH" + responseLength);
return response;
});
Retrofit 2 uses OkHttp internally, and you could configure OkHttp without having to resort to getting raw HTTP response as in Vaiden's answer by adding a custom Interceptor while building an adapter as follows:
private Retrofit createRetrofit() {
return new Retrofit.Builder()
.baseUrl(END_POINT)
// .addConverterFactory(...)
// .addCallAdapterFactory(...)
.client(createClient())
.build();
}
private OkHttpClient createClient() {
OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
okHttpClientBuilder.addInterceptor(createYourInterceptor());
return okHttpClientBuilder.build();
}
The Interceptor interface among other things allows you to access request body for every request you make.
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
// do what you want with request.body().contentLength();
return chain.proceed(request);
}
For this you need to create custom interecptor
please reffere below example
import java.io.IOException;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
public class CustomIntercepter implements Interceptor {
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();///
Response response = chain.proceed(request);
// for request size
long requestLength = request.body().contentLength();
// for response size
long responseLength = response.body().contentLength();
return response;
}
}
`
Now Create Retrofit object
OkHttpClient provideOkHttpClient(CustomIntercepter customIntercepter) {
OkHttpClient.Builder okHttpClient = new OkHttpClient.Builder();
okHttpClient.cache(cache);
okHttpClient.addInterceptor(customIntercepter);
return okHttpClient.build();
}
Retrofit provideRetrofit(Gson gson, OkHttpClient okHttpClient) {
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create(gson))
.baseUrl(SERVER_URL)
.client(okHttpClient)
.build();
return retrofit;
}
You should try accessing the raw HTTP response (Get raw HTTP response with Retrofit):
You begin with a Response object.
This object has a .raw() method that returns the actual HTTP layer's reponse,
in the form of an okhttp3.Response object. Calling .body() would give you a ResponseBody object, which encapsulates the raw response.
You can get the length of the response by calling .contentLength().
I'm just learning Retrofit and OKHttp, now I have an issue.
Every request in my app is POST, just like this:
#FormUrlEncoded
#POST("some url")
Observable<Result> getData(#Field("id") String id);
In every POST, there are two same params. So in a most simple way, I can add two more #Field in every method, for example, #Field("token"),#Field("account"). But I think there must be a smart way.
Then I thought OkHttpClient may solve this.
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
RequestBody body = new FormBody.Builder().add("account", "me")
.add("token", "123456").build();
request = request.newBuilder().post(body).build();
return chain.proceed(request);
}
}).build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("some base url")
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
Or
HttpUrl url = request.url().newBuilder()
.setEncodedQueryParameter("account", "me")
.setEncodedQueryParameter("token", "123456")
.build();
The first method just replace all Field to these two.
The second method just add these two as GET parameters, not POST.
Now I have absolutely no idea how to make this work.
OK...Finally I find a way to do this. But I'm not sure this is the best way.
Here is the code:
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
FormBody.Builder bodyBuilder = new FormBody.Builder();
FormBody b = (FormBody) request.body();
for (int i=0;i<b.size();i++) {
bodyBuilder.addEncoded(b.name(i),b.value(i));
}
bodyBuilder.addEncoded("account", "me").add("token", "123456");
request = request.newBuilder().post(bodyBuilder.build()).build();
return chain.proceed(request);
}
}).build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://some url)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
I get all the #Field from retrofit, then add every key-value params to a new RequestBody, same as these two default params. Now every POST request has "account" and "token".
If there is a better way to do this, please let me know.
You can do that by adding a new request interceptor to the OkHttpClient. Intercept the actual request and get the HttpUrl. The http url is required to add query parameters since it will change the previously generated request url by appending the query parameter name and its value.
OkHttpClient.Builder httpClient =
new OkHttpClient.Builder();
httpClient.addInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request original = chain.request();
HttpUrl originalHttpUrl = original.url();
HttpUrl url = originalHttpUrl.newBuilder()
.addQueryParameter("apikey", "your-actual-api-key")
.build();
// Request customization: add request headers
Request.Builder requestBuilder = original.newBuilder()
.url(url);
Request request = requestBuilder.build();
return chain.proceed(request);
}
});
So some images I request require an authentication header to be added
I am using Retrofit 2.0 which has this OkHttp client with a interceptor to add the user token to the header to every request
okHttpClient.interceptors().add(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request(); //Current Request
Request requestWithToken = null; //The request with the access token which we will use if we have one instead of the original
requestWithToken = originalRequest.newBuilder().addHeader(Constants.UrlParamConstants.HEADER_AUTHORIZATION,String.format(Constants.UrlParamConstants.HEADER_AUTHORIZATION_VALUE, MyApplication.getInstance().getUser().getApiToken())).build();
Response response = chain.proceed((requestWithToken != null ? requestWithToken : originalRequest)); //proceed with the request and get the response
return response;
}
});
I would like to know how can I set the same okHttp client instance for Fresco library.
I am aware that you need to add this dependency to use OkHttp with Fresco but how about setting the client?
compile "com.facebook.fresco:imagepipeline-okhttp:0.8.0+"
At the end of the day I just need to set authentication header for an image request
thanks for reading
http://frescolib.org/docs/using-other-network-layers.html
Context context;
OkHttpClient okHttpClient; // build on your own
ImagePipelineConfig config = OkHttpImagePipelineConfigFactory
.newBuilder(context, okHttpClient)
. // other setters
. // setNetworkFetcher is already called for you
.build();
Fresco.initialize(context, config);