I am trying to sent dynamic headers using Okhttp interceptor, but the problem I am facing is when I am calling setretrofitclient() method at the same time, then the header sent for both request are same. This is happening because as okhttp interceptor went in background thread to execute the request but at the same time in UI thread header value gets changed because of which when okhttp send the request it send new updated header.
String header;
public String getHeader() {
return header;
}
static RetrofitInterface retrofitInterface;;
public RetrofitInterface setretrofitclient(String header) {
this.header = header;
if (retrofit != null) {
return retrofit;
} else {
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
httpClient.addInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request().newBuilder().addHeader("x-param", getHeader()).build();
return chain.proceed(request);
}
});
Retrofit retrofit = new Retrofit.Builder().addConverterFactory(GsonConverterFactory.create()).baseUrl(url).client(httpClient.build()).build();
retrofitInterface = retrofit.create(RetrofitInterface.class);
return retrofitInterface;
}
}
Can anyone please suggest me the design pattern how can I make this work for parallel requests.
Thanks.
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(); }
Am Struggling with one of the issues of being service taking almost 10 mins to reflect the updated results. Actually, am using an API of type Get, the structure of the service is like this:
www.abc.net/wp-json/wp/v2/posts?categories=192&page=1&per_page=2
When I try to call the service from the browser it's showing the updated information, but when I try to call the same service from my android app using retrofit it's delaying the updated response by almost 10 mins.
Here is the code mentioned in my last question about the same :
public class ApiClient {
private static Retrofit retrofit = null;
public static Retrofit getClient() {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
httpClient.addInterceptor(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()
.cacheControl(CacheControl.FORCE_NETWORK)
.addHeader("Cache-Control", "no-cache")
.addHeader("Cache-Control", "no-store");
Request request = requestBuilder.build();
return chain.proceed(request);
}
});
OkHttpClient client = httpClient.build();
retrofit = new Retrofit.Builder()
.baseUrl(ApiInterface.SERVICE_ENDPOINT)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
return retrofit;
}
}
My API Interface
public interface ApiInterface {
String SERVICE_ENDPOINT = "https://example.com/wp-json/wp/v2/";
#GET("posts")
Call<ArrayList<CategoryResponse>> fetchlatestposts(#Query("bloglist")
int bloglist);
}
What can be the issue for not getting the updates response in real time, while as after 10-15 mins of pause it will give the updated results.
The issue was from the server side, WordPress has cache enabled which was causing the issue.
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 am building an Android APP where I use the Internet Game Database API through Mashape market place. I am using Retrofit for the get requests and getting data from the API requires an API key.
I got it to work but the API only return game ids and I want the game names and other information, but I am not sure how to add the fields. This is how Mashape query it:
HttpResponse<String> response = Unirest.get("https://igdbcom-internet-game-database-v1.p.mashape.com/games/?fields=name%2Crelease_dates")
.header("X-Mashape-Key", "API KEY HERE")
.header("Accept", "application/json")
.asString();
and this is my Retrofit Interface
public interface GamesAPIService {
#GET("/games/")
Call<List<GamesResponse>> gameList(#Query("mashape-key") String apikey);
}
I tried to use this
#GET("/games/?fields=name,release_dates")
But no luck, I also tried with #Field but didn't work either. Any ideas? Thanks.
Edit: Just to clarify when I add the "?fields=name,release_dates" I get 401 Unauthorized Error.
Firstly I think you need to add mashape key to all your request.
OkHttpClient httpClient = new OkHttpClient();
httpClient.addInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request().newBuilder()
.addHeader("X-Mashape-Key", "API_KEY_HERE")
.addHeader("Accept", "application/json")
.build();
return chain.proceed(request);
}
});
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://igdbcom-internet-game-database-v1.p.mashape.com")
.client(httpClient)
.build();
And then this is information query.
public interface GamesAPIService {
#GET("/games")
Call<List<GamesResponse>> gameList(#Query("fields") String value);
}
And last thing for calling.
GamesAPIService gamesAPIService = retrofit.create(GamesAPIService.class);
Call<List<GamesResponse>> call = gamesAPIService.gameList("name,release_dates");
if (call!=null){
call.enqueue(new Callback<List<GamesResponse>>() {
#Override
public void onResponse(Call<List<GamesResponse>> call, Response<List<GamesResponse>> response) {
// handle success
}
#Override
public void onFailure(Throwable t) {
// handle failure
}
});
}
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.