HTTP GET-Request in Kotlin/Android Studio - android

I am facing a problem with coding my first Android-App.
I want to build the login-system of the app around my existing webserver/webinterface.
I am using the Fuel-Library, and as far as I can tell, the GET Requests are working fine.
The problem is the response. When I print it out, everything is see is some information about the request itself, but the printed echo from PHP isn't showing up anywhere.
Response printed out:
I/System.out: <-- 200 https://...hidden :)
I/System.out: Response : OK
Length : -1
Body : test
Headers : (11)
Connection : Keep-Alive
Date : Mon, 30 Mar 2020 18:06:39 GMT
X-Android-Selected-Protocol : http/1.1
Server : Apache
X-Powered-By : PHP/7.3.5, PleskLin
Content-Type : text/html; charset=UTF-8
X-Android-Received-Millis : 1585591597000
Vary : Accept-Encoding
X-Android-Response-Source : NETWORK 200
X-Android-Sent-Millis : 1585591596960
Keep-Alive : timeout=5, max=100
The same is happening with POST Requests.
Here is my Kotlin-Code:
val url = "https://myserver.com/testlogin.php?username=".plus(username.toString()).plus("&password=").plus(password.toString())
url.httpGet().responseString{
request, response, result ->
Toast.makeText(this#MainActivity, result.toString(), Toast.LENGTH_LONG).show()
}
And the PHP Code on the Webserver:
<?php $username = $_GET["username"]; $password = $_GET["password"]; echo $username; ?>
I am searching for more than 7 hours now. send help

Try this
url.httpGet().responseString { request, response, result ->
when (result) {
is Result.Failure -> {
val ex = result.getException()
println(ex)
}
is Result.Success -> {
val data = result.get()
println(data)
}
}
}
Official documentation

I just found the problem:
val data = result.get() println(data)
prints the response string of the php file.

Related

Show the actual raw data + HTTPS headers sent by HttpsURLConnection

I have this simple code to connect to my host:
URL url = new URL("https://www.example.com/getResource");
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
m_HttpsConnection.setDoOutput(true);
OutputStream os = m_HttpsConnection.getOutputStream();
DataOutputStream wr = new DataOutputStream(os);
wr.writeBytes("{\"key\":\"value\"}");
wr.flush();
wr.close();
Log.d("MyActivity", "http raw data: " + conn.toString()); <-- this is what I want to achieve!
What I want to see in my logs is the actual HTTP packets that I send to the host like so:
POST /getResource/ HTTP/1.1
Content-Type: application/json
Cache-control: no-cache
Content-Length: 15
{"key":"value"}
How do I do this? Thanks!
For both OkHttpClient and HttpsURLConnection, there is no way to check the complete raw request HTTP packet that you send to a host.
For OkHttpClient, this is the best you can do to check the headers:
class LoggingInterceptor implements Interceptor {
#NotNull
#Override
public Response intercept(#NotNull Chain chain) throws IOException {
Request request = chain.request();
long t1 = System.nanoTime();
logger.info(String.format("Sending request %s",
request.headers().toString()));
Response response = chain.proceed(request);
long t2 = System.nanoTime();
logger.info(String.format("Received response for %s in %.1fms%n%s",
response.request().url(), (t2 - t1) / 1e6d, response.headers()));
return response;
}
}
Please take note that when you did not set any header (Request.Builder.header()), nothing will show in your logs. The same observation holds true for HttpsURLConnection. The HttpsURLConnection.getRequestProperties() will only show what you have set in HttpsConnection.setRequestProperty().
For HTTP response, it is a different story. You can get the entire raw response headers.
For HttpsURLConnection you can use below code:
Map<String, List<String>> map = httpsURLConnection.getHeaderFields();
Set<String> keys = map.keySet();
Log.d(TAG, "https response headers: ");
for (String key : keys) {
List<String> list = map.get(key);
for (String value : list) {
Log.d(TAG, "key: " + key + ", value: " + value);
}
}
This gives you everything in your response packet including the HTTP/1.1 200 OK field:
D/MyActivity: key: null, value: HTTP/1.1 200 OK
D/MyActivity: key: Cache-Control, value: private
D/MyActivity: key: Content-Length, value: 20
D/MyActivity: key: Content-Type, value: application/json
D/MyActivity: key: Date, value: Thu, 22 Aug 2019 09:16:06 GMT
D/MyActivity: key: Server, value: Microsoft-IIS/10.0
I believe you can also get the complete response packet for OkHttpClient. I did not check.

Okhttp3+android has a significant delay between responseHeadersStart and responseHeadersEnd

I am using okhttp 4.0.1 in an Android app and there is a significant delay when receiving the response, particularly the headers. This adds a significant delay time to the users (ranging around 2-5 seconds) per request sent. The time delay is measured using okhttp's EventListenerfrom here https://square.github.io/okhttp/events/
This code is already placed inside an AsyncTask. Note that the delay happens after mCall?.execute
val mBuilder = Request.Builder()
val url = ....
// Add URL
mBuilder.url(url) // Request.Builder
// Request
val req = mBuilder.build()
// Call
var resp: Response? = null
var code = RESPSTATUS_IOEXC
var body = ""
try {
// Execute the call
mCall = mClient.newCall(req)
resp = mCall?.execute()
code = resp?.code?: 0
body = resp?.body?.string()?: ""
} catch (e: ConnectException) {
e.printStackTrace()
code = RESPSTATUS_CONNECTION_FAILED
} catch (e: SocketTimeoutException) {
e.printStackTrace()
code = RESPSTATUS_TIMEOUT
} catch (e: IOException) {
e.printStackTrace()
code = RESPSTATUS_IOEXC
} catch (e: IllegalStateException) {
e.printStackTrace()
code = RESPSTATUS_ALREADY_EXEC
} catch (e: CertificateException) {
e.printStackTrace()
code = RESPSTATUS_INVALID_CERT
} finally {
resp?.close()
}
One of the example messages showing the delay (3s delay retrieving response headers):
[1] dns started!
[1] dns ended!
[1] connect started!
[29] secure connect started!
[46] secure connect ended!
[46] connect ended!
[46] connection acquired!
[46] request headers started!
[47] request headers ended!
[47] response headers started!
[3676] response headers ended!
[3676] response body started!
[3702] response body ended!
[3704] connection released!
[3704] call ended!
Sample of the response headers I am getting
------ header(Server): nginx/1.10.3 (Ubuntu)
------ header(Date): Thu, 08 Aug 2019 15:08:02 GMT
------ header(Content-Type): application/json
------ header(Content-Length): 33071
------ header(Connection): close
------ header(Vary): Content-Type
------ header(Strict-Transport-Security): max-age=15552000; includeSubDomains; preload;
Our iOS team has called the URLs given without any considerable delay (1-2s max), so I do not know if the problem lies in the code or the server itself.
Any help is appreciated. Thanks before

How to get header response in Retrofit in Android?

This is my end point :
#POST("v4/MyStore/data")
Observable<Headers> requestStore(#Body MyStoreRequest request);
I am trying to get response like this :
requestService.requestStore(request)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.computation())
.map(headers -> {
Log.d("Response",""+headers);
return headers;
}).subscribe(headers -> {
Log.d("Response",""+headers);
},
error -> {
Log.d("ERRRROOOR","Error");
});
I am getting error like below:
Exception: retrofit2.adapter.rxjava.HttpException: HTTP 403 Forbidden
While in postman I am getting response:
Connection →keep-alive
Content-Length →0
Content-Type →application/json; charset=utf-8
Date →Mon, 03 Sep 2018 18:47:30 GMT
MYid →f028df50-c8c5-4cce-92e7-70130345ba46
What I am doing wrong here?
You have to use a Response as your response model because your api is entering error stream in with a code 403
#POST("v4/MyStore/data")
Observable<Response<Void>> requestStore(#Body MyStoreRequest request);
now when you consume response
requestService.requestStore(request)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.computation())
.map(response -> {
Log.d("Response",""+response);
return response.header();
}).subscribe(headers -> {
Log.d("Response",""+headers);
},
error -> {
Log.d("ERRRROOOR","Error");
});
response.header() will return you the header you want even when your api fails
Probably you're missing headers in your API request from Android client. As per your comment, you're sending bearer token in Authorization headers.
So, you need to send bearer token along with request body like below
#Headers({
"Authorization: Bearer <your_bearer_token_here>", /* change token here */
"Content-Type: application/json"
})
#POST("v4/MyStore/data")
Observable<Headers> requestStore(#Body MyStoreRequest request);
Example,
#Headers({
"Authorization: Bearer ca0df98d-978c-410b-96ec-4e592a788c18",
"Content-Type: application/json"
})
#POST("v4/MyStore/data")
Observable<Headers> requestStore(#Body MyStoreRequest request);

WireMock proxying not returning any body

My application does post request to url:
https://myserver.domain.com/authenticate/credentials
OkHttp client interceptor shows my headers:
11-17 10:10:56.780 3140-3304/com.myapp.debug D/OkHttp: Content-Type:
application/x-www-form-urlencoded
11-17 10:10:56.780 3140-3304/com.myapp.debug D/OkHttp: Content-Length:
187
11-17 10:10:56.781 3140-3304/com.myapp.debug D/OkHttp: Authorization:
Basic authorisationkeyfortest5430593045903495034905==
11-17 10:10:56.781 3140-3304/com.myapp.debug D/OkHttp:
email=testlogin%40gmail.com&password=test%4012&deviceId=1484564155&deviceLabel=Android%20SDK%20built%20for%20x86_64&deviceType=ANDROID&deviceVersion=23%20%28REL%29
I have created standalone WireMock server and I want redirect every POST request from my APP to my WireMock server. Thats why I have added *.JSON with request definition:
{
"request": {
"method": "POST",
"urlPattern": ".*"
},
"response": {
"proxyBaseUrl" : "https://myserver.domain.com/",
"additionalProxyRequestHeaders": {
"Authorization": "Basic authorisationkeyfortest5430593045903495034905== "
}
}
}
What I expect that should happen:
When I change basepath of my Http client from https://myserver.domain.com/ to http://myserveraddress.com/ - then every request from my app should go to my MockServer. And MockServer according to JSON above should proxy/forward that request to https://myserver.domain.com/ and return the same response - so everything should work fine.
What happens:
Each POST request returns status 200 but body is empty. (it should return authenticated user object)
Question: Is it possible to achieve that? Am I doing something wrong?
Try to add your body in "__files" folder and set path in "bodyFileName"
{
"request": {
"method": "POST",
"urlPattern": ".*"
},
"response": {
"proxyBaseUrl" : "https://myserver.domain.com/",
"additionalProxyRequestHeaders": {
"Authorization": "Basic authorisationkeyfortest5430593045903495034905== "
},
"bodyFileName":".*.json"
}
In JSON file put your answer. For example:
{
"errorCode": 0,
"errorMessage": "",
"result":
{
"filed1":"value",
"filed2":"value"
}
}

Retrofit 2 - POST request became GET?

My POST request keeps sending as GET & got rejected by API endpoint
MyService class
#FormUrlEncoded
#POST("api/users/")
Call<List<User>> getUsers(#FieldMap HashMap<String, String> parameters);
Request code
Gson builder = new GsonBuilder().setLenient().create();
Retrofit client = new Retrofit.Builder()
.baseUrl(Constants.API_ENDPOINT_TEST_URL)
.addConverterFactory(GsonConverterFactory.create(builder))
.build();
mApiService = client.create(MyService.class);
Call<List<User>> call = mApiService.getUsers(mParameters);
call.enqueue(new Callback<List<User>>() {
#Override
public void onResponse(Call<List<User>> call, Response<List<User>> response) {
mResponse = response.body();
mResponseObserver.onFinish(mResponse);
}
#Override
public void onFailure(Call<List<User>> call, Throwable t) {
mResponseObserver.onFailure();
}
});
But server rejects it as it reached the server in GET request form !? Having checked with debugger, I saw that:
rawResponse.request.method = GET
Here is screenshot of watch window showing the retrofit's request object:
As you can see, the request method was GET. But the weird part is in the tag, it shows a request object with POST method?
Am i miss something here?
UPDATE
I added logging interceptor & here is the log:
D/OkHttp: --> POST http://***/api/users/ http/1.1
D/OkHttp: Content-Type: application/x-www-form-urlencoded
D/OkHttp: Content-Length: 56
D/OkHttp: --> END POST
D/OkHttp: <-- 200 OK https://***/api/users/ (388ms)
D/OkHttp: Date: Thu, 01 Sep 2016 11:50:23 GMT
D/OkHttp: Server: Apache
D/OkHttp: X-Powered-By: PHP/5.4.34
D/OkHttp: Cache-Control: max-age=2592000
D/OkHttp: Expires: Sat, 01 Oct 2016 11:50:23 GMT
D/OkHttp: Vary: Accept-Encoding
D/OkHttp: Content-Type: application/json; charset=UTF-8
D/OkHttp: Set-Cookie: SESSION_DEFAULT=***; expires=Sun, 04-Sep-2016 11:50:24 GMT; path=/; HttpOnly
D/OkHttp: Set-Cookie: COOKIE[***]=***; path=/; httponly
D/OkHttp: Connection: close
D/OkHttp: <-- END HTTP
looks like the request is a POST. But, the server still responds with error message, saying that the request method is a GET
Hmm, I'll dig a little bit more into it.
Actually, the issue is the combination of 2 factors:
Wrong request protocol has been made (http instead of https)
Server responded with a weird message on wrong protocol: "GET is not supported".
ANyway, thanks #nshmura for your assistant.
I checked your program with logging, and confirms the POST request is sent.
I recommend you to check like this:
class TestClass {
private void testRequest() {
HashMap<String, String> mParameters = new HashMap<>();
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.HEADERS);
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
httpClient.addInterceptor(logging); // <-- this is the important line!
Gson builder = new GsonBuilder().setLenient().create();
Retrofit client = new Retrofit.Builder()
.baseUrl(Constants.API_ENDPOINT_TEST_URL)
.addConverterFactory(GsonConverterFactory.create(builder))
.client(httpClient.build())
.build();
MyService mApiService = client.create(MyService.class);
Call<List<User>> call = mApiService.getUsers(mParameters);
call.enqueue(new Callback<List<User>>() {
#Override
public void onResponse(Call<List<User>> call, Response<List<User>> response) {
}
#Override
public void onFailure(Call<List<User>> call, Throwable t) {
}
});
}
interface MyService {
#FormUrlEncoded
#POST("api/users/")
Call<List<User>> getUsers(#FieldMap HashMap<String, String> parameters);
}
class User {
}
class Constants {
public static final String API_ENDPOINT_TEST_URL = "http://.........";
}
}
here is request log:
D/OkHttp: --> POST http://......... http/1.1
D/OkHttp: Content-Type: application/x-www-form-urlencoded
D/OkHttp: Content-Length: 0
D/OkHttp: --> END POST
Here is response:
D/OkHttp: <-- 200 OK http://.............../ (167ms)
D/OkHttp: Server: nginx
D/OkHttp: Date: Thu, 01 Sep 2016 11:30:32 GMT
D/OkHttp: Content-Type: text/html; charset=UTF-8
D/OkHttp: Connection: close
....
D/OkHttp: <-- END HTTP
I met a similar problem. In my case, I received in response to 301, redirect and change of method POST -> GET.
First, check your BASE_URL, it must be of the form "h ttps://www.YourSite.com/" www - very important. If everything is in place and the problem still exists, then you can change as described below:
From okhttp wiki and based on this image, you need to change something like this:
...
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
final RequestBody requestBody = new FormBody.Builder().build();
httpClient.addNetworkInterceptor(new Interceptor() {
#Override public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
HttpUrl.Builder builder = request.url().newBuilder();
HttpUrl url = builder.build();
request = request.newBuilder()
.url(url)
.post(requestBody)
.build();
return chain.proceed(request);
}
})
httpClient.addInterceptor(logging);
...
Can u try
#POST("/api/users/")
With slash before "api"?
Also it would be helpful to double check request with Fiddler or smth.
That is partly correct a http client behavior. According to the HTTP spec
If the 307 status code is received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued.
Sometime it is not possible to change backend API. So here a workaround you can add to you interceptor to manually redirect a request with correct method.
fun forceRedirectMethod(chain: Interceptor.Chain, originResponse: Response): Response {
/* TODO
one more request is made; disable followRedirect and make it manually?
*/
if (originResponse.priorResponse()?.code() == 302) {
val priorResponse: Response = originResponse.priorResponse() as Response
val redirectRequest = priorResponse.request()
val builder = originResponse.request().newBuilder()
.method(redirectRequest.method(), redirectRequest.body())
val newRequest = builder.build()
return chain.proceed(newRequest)
} else {
return originResponse
}
}

Categories

Resources