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.
Related
In my scenario, our backend wants to get a unique ID with any request but I read that "OkHttp will potentially repeat your requests on a slow/unreliable connection 'aggressively' until it succeeds." from here and some OkHttp issues. I know I can disable the retry mechanism with retryOnConnectionFailure(false) but I want to enable it to handle connectivity problems. Exactly what I want is, modify the request before silent retry. Can I intercept before sending a silent request?
If you add a networkInterceptor then you should have roughly 1:1 with the calls made to your backend. A normal interceptor may not involve an actual request if you get a cache hit, and it won't see all the retries. So add a networkInterceptor which will get called for each route chosen.
The multiple attempts come from both alternative routes (multiple DNS results) and safely retrying some calls based on the HTTP request or server response code that indicate it is safe to do so.
See https://square.github.io/okhttp/interceptors/ for information.
Choosing between application and network interceptors
Each interceptor chain has relative merits.
Application interceptors
Don’t need to worry about intermediate responses like redirects and retries.
Are always invoked once, even if the HTTP response is served from the cache.
Observe the application’s original intent. Unconcerned with OkHttp-injected headers like If-None-Match.
Permitted to short-circuit and not call Chain.proceed().
Permitted to retry and make multiple calls to Chain.proceed().
Can adjust Call timeouts using withConnectTimeout, withReadTimeout, withWriteTimeout.
Network Interceptors
Able to operate on intermediate responses like redirects and retries.
Not invoked for cached responses that short-circuit the network.
Observe the data just as it will be transmitted over the network.
Access to the Connection that carries the request.
I think you can solve this process with Interceptor. When a server cannot be connected, you can connect to another server.
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
// try the request
Response response = doRequest(chain,request);
int tryCount = 0;
while (response == null && tryCount <= RetryCount) {
String url = request.url().toString();
url = switchServer(url);
Request newRequest = request.newBuilder().url(url).build();
tryCount++;
// retry the request
response = doRequest(chain,newRequest);
}
if(response == null){//important ,should throw an exception here
throw new IOException();
}
return response;
}
private Response doRequest(Chain chain,Request request){
Response response = null;
try{
response = chain.proceed(request);
}catch (Exception e){
}
return response;
}
I currently try to write a android app to setup and controll a ESP8266 on which micropython runs.
On the micropython server I initialize a websocket like this:
def __init__(self, task_manager, setup_mode):
address = socket.getaddrinfo('0.0.0.0', 80)[0][-1]
self._socket = socket.socket()
self._socket.bind(address)
self._socket.listen(1)
self._socket.setblocking(False)
self._socket.settimeout(5)
self._task_manager = task_manager
self._setup_mode = setup_mode
print('New Socket is listening on: ', address)
And then simple listen to incoming connections like this, and then react to the incoming messages. Also the listing is looped to allow the microcontroller logic to update every 5 seconds.
client, address = self._socket.accept()
print("New request from:", address)
Everything is working fine when I send test request using python from my PC. For example a simple request would be something like this:
data = json.dumps({'load': {'type': "is_lighthub", 'data': {}}})
response = requests.post(ip, json=data)
However when I try to make the same post request using OkHttp from an android app, then there is no incoming connection at the ESP.
Here is the android java code:
private void addIfLighthub(final InetAddress address) {
try {
RequestBody body = RequestBody.create(JSON, "{\"load\": {\"type\": \"is_lighthub_server\", \"data\": {}}");
Request request = new Request.Builder()
.url("http://" + address.getHostAddress())
.post(body)
.build();
try (Response response = client.newCall(request).execute()) {
final JSONObject myResponse = new JSONObject(response.body().string());
if((boolean)myResponse.get("is_lighthub")) {
onlineDeviceList.add(address);
}
} catch (IOException e) {
System.out.println(e.getMessage());
}
} catch (JSONException jsonException) {
System.out.println(jsonException.getMessage());
}
}
The odd thing however is that that sample code, if provided with for example the address of my router, does receive the routers default html site ...
So, am I missing something? I fairly new to networking but a simple post request from the phone should be the same as from a python sample code, right?
Or is there a error in my java function?
Thank you guys in advance for the help!
If fixed it myself!
The mistake was that the python test client sended the json seperate, while the okhttp client sended both in one piece.
That made the server timeout while waiting for a second message ...
I am working on an Android app in which a log in post request is made to a webservice. The request returns a cookie which expires in 20 minutes.
Using okhttp3 and this PersistentCookieStore library, I got the cookie to be stored and subsequently added it as request header to access authentication-required get requests (e.g. personal information that are non-public).
The code goes this way,
CookieJar myCookieJar = new PersistentCookieJar(new SetCookieCache(),
new SharedPrefsCookiePersistor(this));
OkHttpClient client = new OkHttpClient.Builder().cookieJar(HttpRequests.cookieJar).build();
I then call a method like this inside an (after I have gone through another log in Async task to get the cookie) Async task to perform a get request that requires authentication,
public static String PostReq(String url, String json) {
RequestBody body = RequestBody.create(JSON, json);
Request request = new Request.Builder()
.url(url)
.addHeader("Cookie", "key=value")
.post(body)
.build();
try (Response response = client.newCall(request).execute()) {
return response.body().string();
}
catch(Exception e){
}
}
The .addHeader("Cookie", "key=value") adds the cookie to the header to tell the webservice that I am authenticated.
Here comes my difficulty. Since the cookie expires after 20 minutes, I would like to be able to access the cookie itself to check for the expiration time and possibly redirect the user to the log in activity by calling the method,
myCookie.expiresAt()
and comparing it to
System.currentTimeMillis()
I tried to look at the PersistentCookieStore codes and found that it uses a SharedPreference with the key "CookiePersistence". I looked inside this file while my emulator was running the app and found it to be empty however.
How would I be able to access this cookie that I have obtained? Much thanks for any advice to be given.
OK, this is old, but I was facing the same problem, and here is how I fixed it.
Hold a reference to your SetCookieCache used to instantiate your CookieJar:
SetCookieCache cookieCache = new SetCookieCache();
CookieJar myCookieJar = new PersistentCookieJar(
cookieCache,
new SharedPrefsCookiePersistor(this)
);
Then use this to find your cookie and check it:
for (Cookie cookie : cookieCache) {
if (cookie.name().equals("cookie_name") && cookie.persistent()) {
//cookie is still good
break;
}
}
Or use cookie.expiresAt() to do your thing.
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 trying to do a http post to my server to check if the login credentials are valid with help of this tutorial. I need to make a request to my server but i have to add Authorization, i get the string with the function getB64Auth from this answer. the function logs the right variable, (the same as i use with postman). But for some reason my program stops running if i run my code. I already tried adding the code from the comments but it didn't help.
What am i doing wrong?
private String getB64Auth (String login, String pass) {
String source=login+":"+pass;
String ret="Basic "+Base64.encodeToString(source.getBytes(),Base64.URL_SAFE| Base64.NO_WRAP);
Log.d("authy", ret);
return ret;
}
/** Called when the user clicks the Login button */
public void login(View view) {
// Getting username and password
EditText userText = (EditText) findViewById(R.id.inputLoginUsername);
EditText passText = (EditText) findViewById(R.id.inputLoginPassword);
String usernameInput = userText.getText().toString();
String passwordInput = passText.getText().toString();
String authorizationString = getB64Auth(usernameInput,passwordInput );
// Do something in response to button
// 1. Create an object of HttpClient
HttpClient httpClient = new DefaultHttpClient();
// 2. Create an object of HttpPost
// I have my real server name down here
HttpPost httpPost = new HttpPost("https://myservername.com/login");
// 3. Add POST parameters
httpPost.setHeader("Authorization", authorizationString);
// 5. Finally making an HTTP POST request
try {
HttpResponse response = httpClient.execute(httpPost);
Log.d("win", "win1");
// write response to log
Log.d("Http Post Response:", response.toString());
} catch (ClientProtocolException e) {
Log.d("fail", "Fail 3");
// Log exception
e.printStackTrace();
} catch (IOException e) {
Log.d("fail", "Fail 4");
// Log exception
e.printStackTrace();
}
}
When i run my code the app stops working, i can find the log authy but i cant find any fail succes logs.
The things i have changed in the example are step 3.
ive added my authorization there.
and removed step 4 cause i dont need it.
Working postman example, with the same request i want to make in android.
You can see I get a response, and only set Authorization on my request.
I cant find any decent post/authorization tutorials so i hope i'm looking at the right direction.
It's an android 4.* project
Just a few suggestions about such issues:
Check permissions (INTERNET is the one you would need)
Applications like Charles / Fiddler let you sniff the Http traffic from the device so you could investigate what is being sent
If the application is crashing - check the LogCat messages (for example it could contain a message explaining which permission is missing)
Regarding this message:
The application may be doing too much work on its main thread.
This usually means that you are doing some heavy operations in the main thread - for example parsing the Json from the Http response. Generally you'd like to do all these operations in a background thread and use the main one to update the UI only.