I am using multipart for uploading data to server. The problem is that the backend developer told me that the file I was uploading became corrupted during upload.
So is there any way to test those file locally? Like can I convert a file to multipart and then reconvert it to file to test it?
I am using Retrofit 2
Thanks
ask your backend developer whether he want file as binary or as base64 if it is image and then send file accordingly
you can also log what data is being sent in body of your post
here is code to log data you are sending through retrofit
public class RetrofitClient {
private RetrofitClient() {
}
public static Retrofit getApiClient(String baseHost) {
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
// set your desired log level
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
httpClient.addInterceptor(logging);
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()
.header(Util.HEADER_KEY, ""+Util.HEADER_VALUE); // <-- this is the important line
Request request = requestBuilder.build();
return chain.proceed(request);
}
});
OkHttpClient client = httpClient.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseHost)
.addConverterFactory(new NullOnEmptyConverterFactory())
.addConverterFactory(GsonConverterFactory.create())
.client(httpClient.build())
.build();
return retrofit;
}
}
Related
I using Retrofit to making API call. All API call is working fine except one where its returning huge response around 15k records.
Issue is when made call progress bar is being shown infinitely until I get response. And as response too huge getting OOM exception.
As an solution I found that need to use #Streaming annotation. I used that but didn't get intermediate callback. I want API should return chunk of response one by one.
Please help me.
public static ServiceInterface getServiceAPIClient() {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
Gson gson = new GsonBuilder()
.setLenient()
.create();
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(
new Interceptor() {
#Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request request = chain.request();
Request.Builder builder = request.newBuilder();
builder = request.newBuilder();
if (!TextUtils.isEmpty(PrefsHelper.getAccessTokenEdrm())) {
builder.addHeader(AUTHORIZATION, PrefsHelper.getAccessTokenEdrm());
}
builder.addHeader(API_VERSION, "1.0")
.addHeader("Accept", "application/json");
request = builder.build();
return chain.proceed(request);
}
}).connectTimeout(5, TimeUnit.MINUTES) .readTimeout(5, TimeUnit.MINUTES).addInterceptor(interceptor)
.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.client(client)
.build();
return retrofit.create(ServiceInterface.class);
}
API Method
#POST(EdrmConstants.SEARCH_DOCUMENTS)
#Streaming
Observable<ResponseBody> searchDocuments(#Body DocumentRequest documentRequest);
15k records is too match.
Retrofit needs time to make http request and makes serialization to your ResponseBody.class
I sure serialization takes main time.
I guess most right solution is to edit request on server side to split data on pages with 200-500 records.
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'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);
}
});