So, I was doing my project on localhost and everything ran smooth. I was able to make request call to the server and getting the response from my android. No problem. Then I got a ec2 from AWS and did't map to any domain name. SO, When I use curl or postman to make the request it works totally fine. Everything works great. But the same URL I try to make a request from my Retrofit it says
HTTP FAILED: java.net.UnknownHostException: Unable to resolve host "ec2-11-130-81-251.ap-south-1.compute.amazonaws.comapi": No address associated with hostname
I also made sure that I have given internet permission in my phone and everything. So, is it a must to have a domain name when making network request from an android phone? is there any way to bypass such things?
here is my retrofit singleton class if it finds useful. Thanks
public class ApiClient {
// public static final String BASE_LOCAL_URL = "http://192.168.1.4:3000/";
// public static final String BASE_LOCAL_EMULATOR_URL = "http://10.0.2.2:3000/";
public static final String SERVIER_LOGIN="ec2-11-130-81-251.ap-south-1.compute.amazonaws.comapi";
public static final String BASE_URL = SERVIER_LOGIN;
private static Retrofit retrofit = null;
private ApiClient() {
if (retrofit != null) {
throw new RuntimeException("Use getInstance() method to get the single instance of this class.");
}
}
public static synchronized Retrofit getClient(Context context) {
if (retrofit == null) {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.level(HttpLoggingInterceptor.Level.BODY);
AuthInterceptor authInterceptor = new AuthInterceptor(context);
OkHttpClient client = new OkHttpClient.Builder().
addInterceptor(authInterceptor).
readTimeout(60, TimeUnit.SECONDS)
.writeTimeout(60, TimeUnit.SECONDS)
.connectTimeout(60, TimeUnit.SECONDS)
.addInterceptor(interceptor)
.build();
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create(getGson()))
.client(client)
.build();
return retrofit;
}
return retrofit;
}
private static Gson getGson() {
return new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS").create();
}
}
Resolved by adding a slash in your base URL. That is if your base URL is www.some_base_url.com it should be www.some_base_url.com/ when initiating a retrofit instance. So. Make sure you're adding a slash in the end if it gives that error.
Related
we are having a network error, and are not sure what could be causing it. We upload data from an Android app, and most of the time it works great.
Data are sent with Retrofit and OKHttp3 using an interface:
private static String BASE_URL = "https://backend.ourapp.com/api/";
private static String cert1 = ...;
private static String cert2 = ...;
private static String cert3 = ...;
public static Retrofit retrofit;
static Gson gson = new GsonBuilder()
.setLenient()
.create();
static CertificatePinner certificatePinner = new CertificatePinner.Builder()
.add("backend.ourapp.com", cert1)
.add("backend.ourapp.com", cert2)
.add("backend.ourapp.com", cert3)
.build();
public static HttpLoggingInterceptor logging =
new HttpLoggingInterceptor()
.setLevel(HttpLoggingInterceptor.Level.BODY);
public static OkHttpClient okHttpClient = new OkHttpClient.Builder()
.readTimeout(180, TimeUnit.SECONDS)
.connectTimeout(180, TimeUnit.SECONDS)
.certificatePinner(certificatePinner)
.addInterceptor(logging)
.build();
public static Retrofit getClient(String url) {
if (retrofit == null) {
retrofit = new Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient)
.build();
}
return retrofit;
}
public static ApiInterface apiInterface() {
retrofit = null;
return ApiClient.getClient(BASE_URL).create(ApiInterface.class);
}
But then all of a sudden, and randomly, we start having issues. Error from backend log is:
ERROR org.apache.juli.logging.DirectJDKLog [http-nio-7200-exec-1] Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception
org.springframework.security.web.firewall.RequestRejectedException: The request was rejected because the URL contained a potentially malicious String ";"
We understand this is part of StrictHttpFirewall, and aren't looking to use .setAllowSemicolon(true);.
But we are confused why this is happening, because we aren't, as far as we know, appending anything to our URL. It's an error that also seems to pop up randomly, and then disappear randomly. It also isn't universal- a user will start having the problem while others are OK, and then they will be fine. It typically happens with mobile data networks and not wifi.
Suggestions?? Other things we should look at? Don't suppose it could somehow be certificate related? We have set the timeouts fairly liberally because our app is used on networks that are often slow, but if this particular error doesn't happen, upload is usually successful. We are using retrofit 2.4 and okhttp3 3.10.
Thanks
It appears that the problem is resolved by simply updating Retrofit to 2.9.0 and OkHttp3 to 4.9.1.
I have an android app already uploaded to store and working fine, sometimes when a lot of users open the app at the same time (eg. when sending a notification) our servers are getting overloaded and stops responding for about 10 to 15 minutes. I'm using Retrofit 2 to send requests to our server from the app, I've checked all the app requests there are no places where the request is happening when it shouldn't or needed, finally, I added a logging interceptor to retrofit to track the requests and I was surprised that each request is being called more than ten times for no apparent reason! as you can see in the following image:
This is happening with all requests called from the app for no apparent reason. My service generator for Retrofit 2 is the following:
private static OkHttpClient.Builder httpClient
= new OkHttpClient.Builder().connectTimeout(10000, TimeUnit.SECONDS)
.readTimeout(10000, TimeUnit.SECONDS).addInterceptor(new FakeInterceptor())
.addNetworkInterceptor(new StethoInterceptor())
.retryOnConnectionFailure(false);
private static Gson gson = new GsonBuilder()
.registerTypeAdapter(Date.class, new DateDeserializer())
.create();
private static Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(API_BASE_URL));
public static <S> S createService(Class<S> serviceClass) {
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BASIC);
httpClient.addInterceptor(logging);
Retrofit retrofit = builder.client(httpClient.build()).build();
return retrofit.create(serviceClass);
}
I am sure request is only called once from my code but I have no idea why Retrofit is making all these useless and unnecessary requests. What might be the problem? Thanks in advance, any help is much appreciated.
It's because you are creating multiple instances of the Retrofit client. You should declare a static instance of Retrofit in your class and change
Retrofit retrofit = builder.client(httpClient.build()).build();
to
if(retrofit == null) {
retrofit = builder.client(httpClient.build()).build();
}
Reference: https://github.com/square/retrofit/issues/1724
i am trying to learn Retrofit 2.0 and tried example at http://tutorialwing.com/android-retrofit-library/
but as i go through tutorial i found that it is saying,
base url (https://api.stackexchange.com) + end url("/2.2/questions?order=desc&sort=creation&site=stackoverflow"") = final url ("https://api.stackexchange.com/2.2/search?order=desc&sort=activity&tagged=android&site=stackoverflow".
)
but how search is appended automatically although it is not present in end url.below is my code for making request to API.
public class ApiClient {
public static final String API_BASE_URL = "https://api.stackoverflow.com";
private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
private static Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create());
public static <S> S createService(Class<S> serviceClass) {
HttpLoggingInterceptor interceptor=new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BASIC);
httpClient.addInterceptor(interceptor);
Retrofit retrofit = builder.client(httpClient.build()).build();
return retrofit.create(serviceClass);
}
}
APIinterface.java
#GET("/2.2/search/{order}/{sort}/{tagged}&site=stackoverflow")
Call<ArrayList<Questions>>loadQuestions(#Query("order")String order, #Query("sort")String sort, #Query("tagged")String tag);
but i am not getting any result. after placing interceptor i was able to see url of request is : https://api.stackoverflow.com/2.2/search/%7Border%7D/%7Bsort%7D/%7Btagged%7D&site=stackoverflow?order=desc&sort=activity&tagged=android and after hitting this url it redirect me to this url : https://api.stackexchange.com/docs/api-v1-shutdown?order=desc&sort=activity&tagged=android i am not able to find where i was made mistake. any help is appreciated.
order, sort and tagged are part of the Path of the url, so you need to use the #Path annotation for that. The only query is site=stackoverflow.
#GET("/2.2/search/{order}/{sort}/{tagged}&site=stackoverflow")
Call<ArrayList<Questions>>loadQuestions(#Path("order")String order, #Path("sort")String sort, #Path("tagged")String tag, #Query("site") siteName);
should yeld the url you want.
Edit: if you want to query https://api.stackexchange.com/2.2/search?order=desc&sort=activity&tagged=android&site=stackoverflow then your definition should be
#GET("/2.2/search")
Call<ArrayList<Questions>>loadQuestions(#Query("order")String order, #Query("sort")String sort, #Query("tagged")String tag, #Query("site") siteName);
or alternatively you can use #QueryMap to provide a single argument
i'm still new with singletons. I'm trying to use the DRY methode, but i'm not sure if it's correct. Below you find the class Authorization which i use to create a OkHttpClient and Retrofit.Builder. I'm not sure if it's the right way:
public class Authorization {
private static Retrofit retrofit = null;
public static Retrofit authorize(Activity activity){
final String token = SharedPreferencesMethods.getFromSharedPreferences(activity, activity.getString(R.string.token));
OkHttpClient client = new OkHttpClient();
client.interceptors().add(new Interceptor() {
#Override
public com.squareup.okhttp.Response intercept(Chain chain) throws IOException {
Request newRequest =
chain.request().newBuilder()
.addHeader("Authorization", "Bearer " + token).build();
return chain.proceed(newRequest);
}
});
if(retrofit == null){
retrofit = new Retrofit.Builder()
//10.0.3.2 for localhost
.baseUrl("http://teamh-spring.herokuapp.com")
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
The return value of the method authorize is returning a retrofit object.
Is it a singleton?
Here i call the api
CirkelsessieAPI cirkelsessieAPI = Authorization.authorize(getActivity()).create(CirkelsessieAPI.class);
Call<List<Cirkelsessie>> call = cirkelsessieAPI.getCirkelsessies();
// more code here
Thank you!
No it's not. A singleton is a design pattern that restricts the instanciation of a class to one object. I'm sure you can see why you can instantiate more than one Authorization object, and while the class "Authorization" restricts the instanciation of the class Retrofit to one object for its attribute, it can't in any way restricts someone else from instantiating another Retrofit object somewhere else.
I have set a global timeout in my Retrofit adapter by doing
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.setReadTimeout(20, TimeUnit.SECONDS);
okHttpClient.setConnectTimeout(20, TimeUnit.SECONDS);
retrofit = new Retrofit.Builder()
.client(okHttpClient)
.build();
Great! But I would like to set an specific timeout for certain requests
E.g.
public interface MyAPI {
#GET()
Call<Void> notImportant (#Url String url);
#GET
Call<Void> veryImportant(#Url String url);
So veryImportant calls I would like a timeout of 35 seconds but notImportant the default
Is this possible?
My research has fallen flat.
I came across this however but not sure if it will work in Retrofit
https://github.com/square/okhttp/wiki/Recipes#per-call-configuration
Thank you for reading. Please help.
You can do that by creating overloaded method of your retrofit object factory method. It's maybe look like this.
public class RestClient {
public static final int DEFAULT_TIMEOUT = 20;
public static <S> S createService(Class<S> serviceClass) {
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
OkHttpClient client = httpClient.build();
okHttpClient.setReadTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
okHttpClient.setConnectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
Retrofit retrofit = new Retrofit.Builder().baseUrl(BASE_URL)
.client(client)
.build();
return retrofit.create(serviceClass);
}
public static <S> S createService(Class<S> serviceClass, int timeout) {
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
OkHttpClient client = httpClient.build();
okHttpClient.setReadTimeout(timeout, TimeUnit.SECONDS);
okHttpClient.setConnectTimeout(timeout, TimeUnit.SECONDS);
Retrofit retrofit = new Retrofit.Builder().baseUrl(APIConfig.BASE_URL)
.client(client)
.build();
return retrofit.create(serviceClass);
}
}
if you want to call api with default timout, you can call it look like this.
MyAPI api = RestClient.createService(MyAPI.class);
api.notImportant();
And use the second one if you want to call api with authentication:
int timeout = 35;
MyAPI api2 = RestClient.createService(MYAPI.class, timeout);
api2.veryImportant();
Another solution is by creating different method with different OkHttpClient configuration instead of creating overloaded method. Hope this solution fix your problem.