I want to change the read timeout on OkHttp client using retrofit for one api call. To be clear, I have one end point that can take very long, I need to increase it's timeout and only the timeout for that one api call. Is there a way I can do this through annotations? Is there a way I can do this without changing the timeouts for the rest of the app?
I'm facing a similar situation. I solve my problem providing two Api instances in my ApiModule, each one with your own OkHttpClient. Use #Named to identify each one.
I tried to avoid providing two instances only for a timeout configuration, seems a little strange for me, but since my API instance is a singleton (for performance), I could not see other solution.
You can actually do a per call configuration
Copy the default builder and make another client
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
Request request = new Request.Builder()
.url("http://blah_blah_api.com/") // This URL is served with a 1 second delay.
.build();
try {
// Copy to customize OkHttp for this request.
OkHttpClient copy = client.newBuilder()
.readTimeout(500, TimeUnit.MILLISECONDS)
.build();
Response response = copy.newCall(request).execute();
System.out.println("Response 1 succeeded: " + response);
} catch (IOException e) {
System.out.println("Response 1 failed: " + e);
}
try {
// Copy to customize OkHttp for this request.
OkHttpClient copy = client.newBuilder()
.readTimeout(3000, TimeUnit.MILLISECONDS)
.build();
Response response = copy.newCall(request).execute();
System.out.println("Response 2 succeeded: " + response);
} catch (IOException e) {
System.out.println("Response 2 failed: " + e);
}
}
Related
Hello I am trying to begin an Android app in Kotlin. I have been trying to find a way to simply send and receive data from an android app to a simple HTTP server I made on my computer. The idea I am hoping is just make an app with a text box on it and a send button. When I press the send button it sends it to the simple http server (whether I use IP address or URL isn't Important)
This is just simply a proof of concept that I can make my own simple HTTP Server and get the app to send and receive from it.
I am essentially trying to do a server-client architecture between an android app and a computer. I can get this concept to work between two computer applications (python, java, C++ etc) but not how to do it in android. I keep looking for other answers on here but still come up short.
to be specific do I need enable certain features within the configurations file or a library that will allow the task to be done in the background?
Thank you for your help in advance.
If you want to connect of server for sending requests (POST and GET) then follow this code
public void callApi(String urls,String calledFor) {
try {
HttpGet httppost = new HttpGet(urls);
HttpClient httpclient = new DefaultHttpClient();
HttpResponse response = httpclient.execute(httppost);
int status = response.getStatusLine().getStatusCode();
if (status == 200) {
HttpEntity entity = response.getEntity();
String data = EntityUtils.toString(entity);
JSONObject jsono = new JSONObject(data);
JSONObject json = jsono.getJSONObject("data");
}
} catch (ParseException e1) {
e1.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
}
}
ktor is a wonderful HTTP client that you can use for Android. It is developed by JetBrains, who are also authors of Kotlin, so it takes advantage of the features of the language:
You will need to add the ktor client for Android in build.gradle:
implementation "io.ktor:ktor-client-android:$ktor_version"
Then set up your client like this:
val client = HttpClient(Android) {
// setting these properties is optional; you don't need to if you wish to use the defaults
engine {
connectTimeout = 100_000
socketTimeout = 100_000
}
}
At last you can make HTTP requests like so (example from here): (the use method is to automatically close it at the end, make sure you read about releasing resources)
val resp: String = client.use {
val htmlContent = it.get<String>("https://en.wikipedia.org/wiki/Main_Page")
println(htmlContent)
// same as
val content: String = it.get("https://en.wikipedia.org/wiki/Main_Page")
content
}
Post Api request Using okHttp in Kotlin (Android)
follow steps
You will need to add the dependencies in build.gradle(:app)
implementation("com.squareup.okhttp3:okhttp:4.9.0")
request code here
fun runPostApi() {
var url = "https://reqres.in/api/users"
// add parameter
val formBody = FormBody.Builder().add("name", " Parker")
.build()
// creating request
var request = Request.Builder().url(url)
.post(formBody)
.build()
var client = OkHttpClient();
client.newCall(request).enqueue(object : Callback {
override fun onResponse(call: Call, response: Response) {
println(response.body?.string())
}
override fun onFailure(call: Call, e: IOException) {
println(e.message.toString())
}
})}
for more information link here below
https://square.github.io/okhttp/recipes/
In my app I make a simple get request via okhttp (this is simplified a bit, but you get the gist)
Request request = new Request.Builder()
.url(url)
.get()
.build();
try {
Response response = getOkHttpClient().newCall(request).execute();
if (response.isSuccessful()) {
return response.body().string();
} else {
return "";
}
}
catch (Exception e) {
Log.e(TAG, "Exception: ", e);
return "";
}
The url is a http url.
The api is my clients api and the call works fine outside their office network, unfortunately it does not work inside their office network.
Inside their network the response is 200 but there is no data attached to it (response.body().string() returns an empty string), however the request works just fine in the browser inside their network.
So what could the difference be between making the request inside their network from the app, versus inside their network in the browser? Could I spoof a browser user agent and that would fix it?
We do not know what was causing this, apparently their IT department made some sort of unrelated change to the network and now it works.
I am using the Dirble Api and I am trying to test it to even get some results back but I think I might be doing it the wrong way. This is how I have been trying:
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://api.dirble.com/v2/songs?token={MY_PROVIDED_ACCESS_TOKEN}")
.build();
try {
Response response = client.newCall(request).execute();
System.out.println("Test " + response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
But I keep getting the error:
{"error":"Unauthorized. Invalid or expired token."}
I assumed that this meant the tokens they provided me are just not functioning. So I generated a new one and same result.
This is there guidelines:
https://dirble.com/api-doc#introduction
I cant see anything I am doing wrong but since I am a novice in http requests, I would like to check there is nothing wrong with how I am doing it before I contact them to say the my access codes aren't working.
I am making an HTTP GET request to a Web Server using the code below:
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
Request request = new Request.Builder()
.url("http://publicobject.com/helloworld.txt")
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
Headers responseHeaders = response.headers();
for (int i = 0; i < responseHeaders.size(); i++) {
System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
}
System.out.println(response.body().string());
}
According to OkHttp document as shown below, okhttp3 execute calls will throw IOException if the request could not be executed due to cancellation, a connectivity problem or timeout.
Throws:
IOException - if the request could not be executed due to cancellation, a connectivity problem or timeout. Because networks can fail during an exchange, it is possible that the remote server accepted the request before the failure.
I would like to know if there's a way to know if IOException was due to the request getting timed out?
Although I could not find any information about timeout exception in okHttp3 documentation, looking at tests here shows that a SocketTimeoutException exception will be raised in case of timeouts.
So, to answer my own question, we can catch SocketTimeoutException first in order to know if IOException was due to the request getting timed out like below:
try {
// make http request
} catch (SocketTimeoutException e) {
// request timed out
} catch (IOException e) {
// some other error
}
I am attempting to call a put method on my server using OkHttp from an Android application.
This is the api method signature:
public void Put(int userId, string regId)
{
}
This is the Android code to call the above method:
private boolean SendGCMRegIdToServer(String registrationId, Integer userId) throws IOException {
HttpUrl url = new HttpUrl.Builder()
.scheme("http")
.host(serverApiHost)
.addPathSegment("AppDashboard")
.addPathSegment("api")
.addPathSegment("GCM/")
.build();
MediaType JSON
= MediaType.parse("application/json; charset=utf-8");
String json = "{'userId':" + userId + ","
+ "'regId':'" + registrationId + "'"
+ "}";
RequestBody requestBody = RequestBody.create(JSON, json);
Request request = new Request.Builder()
.url(url)
.put(requestBody)
.build();
//this should post the data to my server
Response response = client.newCall(request).execute();
if(response.code() == 400)
return false;
return true;
}
Now the problem is I am getting the error code 405 in the response saying Method not allowed, but I cannot see where the problem is because I can successfully call the method using Postman on the server itself as below:
http://localhost/AppDashboard/api/GCM?userId=5®Id=123
I'm thinking it may have something to do with an integer or string being passed incorrectly in the JSON string, but cannot see why this isn't working.
i had the same problem and server was returning 405 . after some search i realized that is a configuration problem on IIS that does not let put requests. so there is no problem in android code and you should config your server to let this kind of requests.
see this , this and this
Ok thanks for replies guys but seems I was getting a little confused between the two methods I was using to pass the params to my API.
Here's what I did:
changed the signature of the method to post with a param [FromBody] as a Model (only supports one paramater)...
public void Post([FromBody]UserGcmRegIdModel model)
{
}
I was then able to change my method call to the following using a nicer JSONBuilder and using .post in the request builder rather than .put
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("UserId", userId);
jsonObject.put("RegId", registrationId);
} catch (JSONException e) {
e.printStackTrace();
}
String json = jsonObject.toString();
RequestBody requestBody = RequestBody.create(JSON, json);
Request request = new Request.Builder()
.url(url)
.post(requestBody)
.build();
I still don't know if there is a problem with put() methods on IIS but using a post in my case was absolutely fine so I'm going with that...
I see two different approaches in your REST api calls. In the one of OkHttp you send a PUT method with a JSON object serialized, and in POSTMAN you send a PUT (although I guess you do a GET) request with the parameters within the URL, I mean not in JSON body structure.
Anyway, HTTP 405 is telling you that your backend does not support the PUT method, and probably it's expecting a POST method with the "X-HTTP-Method-Override:PUT" HTTP header since POST is more standard method in REST than PUT.
What would I do is check your POSTMAN request carefully and adjust the one of Android to be the same method, parameters and headers, not more.
Answer Update (as question has been updated)
Of course there is a problem with that verb, as I said above IIS handles only the standard methods and PUT is not one of those. You have three choices:
Change your PUT to POST.
Use POST with X-HTTP-Method-Override to PUT. (reference)
Modify IIS config to support non standard REST methods. I
personally wouldn't suggest the 3rd one, since it's attached to the
backend config (e.g. imagine you change IIS to NancyFX).