HTTP response is empty - android

I am using okHTTP to make an https call to a nodejs/express server. The server returns a json string
{"result" : true}
This json string is shown as {"result":true} in the browser, however when I try to read the response using OkHTTp, I get the following response:
<h1>Not Found</h1>
<h2></h2>
<pre></pre>
There is no json response to be found. Here is the Okhttp code I am using.
public static void sendCredentialsWithPost(LinkedHashMap<String, String> data, String serverUrl, Callback callback) {
Object[] keys = data.keySet().toArray();
FormBody.Builder formBodyBuilder = new FormBody.Builder();
for(Object k : keys) {
String key = (String) k;
formBodyBuilder.add(key, data.get(key).toString());
}
RequestBody formBody = formBodyBuilder.build();
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(serverUrl)
.post(formBody)
.build();
Log.e("wingoku", "url is: "+ serverUrl);
client.newCall(request).enqueue(callback);
}
This is the code for parsing the okhttp response:
#Override
public void onResponse(Call call, Response response) throws IOException {
try {
String serverResponse = response.body().string();
}
What am I doing wrong? How can I fix it?

Related

How to pass Method type like POST, GET in retrofit dynamically in Android

#GET
fun getAccountInfo(
#Url url: String, #HeaderMap headers: Map<String, String>?
): Call<AccountInfoModel.Response>
How to pass this get method dynamically instead of declaring static
You cannot use dynamic http methods in retrofit.
You can use okhttp for this to achieve please find my answer below
package in.silentsudo.test;
import com.google.gson.JsonObject;
import okhttp3.*;
import java.io.IOException;
public class OkHttpMain {
public static void main(String[] args) throws IOException {
OkHttpClient client = new OkHttpClient();
final String host = "https://reqres.in/";
System.out.println(get(host + "api/users/1", client));
JsonObject postBody = new JsonObject();
postBody.addProperty("name", "morpheus");
postBody.addProperty("job", "leader");
System.out.println(post(host + "api/users", postBody.toString(), client));
}
static String get(String url, OkHttpClient client) throws IOException {
Request request = new Request.Builder()
.get()
.url(url)
.build();
try (Response response = client.newCall(request).execute()) {
return response.body().string();
}
}
static String post(String url, String json, OkHttpClient client) throws IOException {
final MediaType JSON
= MediaType.get("application/json; charset=utf-8");
RequestBody body = RequestBody.create(json, JSON);
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
try (Response response = client.newCall(request).execute()) {
return response.body().string();
}
}
}
OkHttp Reference: https://github.com/square/okhttp
You can add custom HTTP request method type (like GET, POST, etc). Please find below answer to understand it.
Kotlin
interface RetrofitService {
#HTTP(method = "CUSTOM_TYPE", path = "custom/urlwithendpoint/")
fun methodName() : Call<RequestBody>
// if you want to call with a request body
#HTTP(method = "CUSTOM_TYPE", path = "custom/urlwithendpoint/", hasBody = true)
fun methodName(#Body params: RequestBody) : Call<RequestBody>
}
JAVA
interface RetrofitService {
#HTTP(method = "CUSTOM_TYPE", path = "custom/urlwithendpoint/")
Call<RequestBody> methodName();
// if you want to call with a request body
#HTTP(method = "CUSTOM_TYPE", path = "custom/urlwithendpoint/", hasBody = true)
Call<RequestBody> methodName(#Body RequestBody params);
}

Separate Class for OkHttp Requests

I use OkHttp for requests to my raspberry. I am thinking about putting the requests in a separate class.
Currently I have one method to send requests. The code is as follows:
private void sendRequest(String url, JSONObject json) {
Log.d(TAG, "sendRequest: Das Json: " + json);
// Authentication for the request to raspberry
OkHttpClient.Builder client = new OkHttpClient.Builder();
client.authenticator(new Authenticator() {
#Override
public Request authenticate(Route route, Response response) throws IOException {
String credential = Credentials.basic("username", "password");
return response.request().newBuilder()
.header("Authorization", credential)
.build();
}
});
// Sending out the request to the raspberry
OkHttpClient okHttpClient = client.build();
RequestBody body = RequestBody.create(null, new byte[]{});
if( json != null) {
body = RequestBody.create(MediaType.parse(
"application/json"),
json.toString()
);
}
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
okHttpClient.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
Log.d(LOG, "Big Fail");
e.printStackTrace();
}
#Override
public void onResponse(Call call, Response response) throws IOException {
try {
ResponseBody responseBody = response.body();
if( !response.isSuccessful() ) {
Log.d(TAG, "onResponse: We are in !response.successful()");
throw new IOException("Response not successful: " + response );
}
Log.d(LOG, "onResponse: Response is: " + responseBody.string());
} catch (Exception e) {
e.printStackTrace();
Log.d(LOG, "onResponse: failed!" + e);
}
}
});
}
Here is an example how the sendRequest() function is called:
private void makePremixCall(Premix premix) {
JSONArray jsonArray = new JSONArray();
ArrayList<Premixable> usedPremixables = premix.getUsedPremixables();
for(Premixable usedPremixable: usedPremixables) {
try {
JSONObject jsonObject = new JSONObject();
jsonObject.put("Silo", usedPremixable.getmSilo());
jsonObject.put("Gramm", usedPremixable.getmKgPerCow() * mFeeding.getmNumberOfCows());
jsonArray.put(jsonObject);
} catch (JSONException e) {
e.printStackTrace();
}
}
try {
JSONObject jsonObject = new JSONObject();
jsonObject.put("Components", jsonArray);
sendRequest("http://192.168.178.49:5000/evaluatePost", jsonObject);
} catch (JSONException e) {
e.printStackTrace();
Log.d(TAG, "makePremixCall: " + e);
}
}
My problem with this: I would like to have a separate class, which offers the function makePremix(Premix premix) and other functions that I need.
The only solution that comes to my mind is implementing the requests synchronously in the separate class and call that separate class in an AsyncTask in the class I am working in.
Do I oversee something? Is there a way to create a separate class and still use the OkHttp enqueue method?
You could extract makePremix(Premix premix) in a separate class and make sendRequest() public (or maybe package-private depending on your use case).
public void sendRequest(String url, JSONObject json)
However since sendRequest is generic and can be used by any other makeAnotherCall() in some other class you would need to get back result of every requests. Hence you can extract the Callback out of sendRequest()
public void sendRequest(String url, JSONObject json, Callback callback)
Now your sendRequest will look like
private void sendRequest(String url, JSONObject json) {
Log.d(TAG, "sendRequest: Das Json: " + json);
// Authentication for the request to raspberry
OkHttpClient.Builder client = new OkHttpClient.Builder();
client.authenticator(new Authenticator() {
#Override
public Request authenticate(Route route, Response response) throws IOException {
String credential = Credentials.basic("username", "password");
return response.request().newBuilder()
.header("Authorization", credential)
.build();
}
});
// Sending out the request to the raspberry
OkHttpClient okHttpClient = client.build();
RequestBody body = RequestBody.create(null, new byte[]{});
if( json != null) {
body = RequestBody.create(MediaType.parse(
"application/json"),
json.toString()
);
}
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
okHttpClient.newCall(request).enqueue(callback);
}
Hope it makes sense!
Also as a side note, see that you are creating a new OkHttp Client every time you call sendRequest. You could probably optimise memory here by caching the client and reusing it.

Android JSON POST with OKHTTP

I´m looking for a solution to implement a JSON-POST request with OKHTTP. I´ve got an HTTP-Client.java file which handles all the methods (POST, GET, PUT, DELETE) and in the RegisterActivity I´d like to POST the user-data (from the input fields) JSON-formatted to the server.
This is my HTTP-Client.java
public class HttpClient{
public static final MediaType JSON
= MediaType.parse("application/json; charset=utf-8");
public static OkHttpClient client = new OkHttpClient.Builder()
.cookieJar(new CookieJar() {
private final HashMap<String, List<Cookie>> cookieStore = new HashMap<>();
#Override
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
cookieStore.put(url.host(), cookies);
}
#Override
public List<Cookie> loadForRequest(HttpUrl url) {
List<Cookie> cookies = cookieStore.get(url.host());
return cookies != null ? cookies : new ArrayList<Cookie>();
}
})
.build();
public static Call post(String url, String json, Callback callback) throws IOException {
RequestBody body = RequestBody.create(JSON, json);
Request request = new Request.Builder()
.url(url)
.post(body.create(JSON, json))
.build();
Call call = client.newCall(request);
call.enqueue(callback);
return call;
}
}
... and this is the onClick-Part from the RegisterActivity
btnRegRegister.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//TODO
String registerData = "{\"email\":\"" + etRegisterEmail.getText().toString() + "\",\"password\":\"" + etRegisterPasswort.getText().toString() + "\"}";
try {
HttpClient.post(ABSOLUTE_URL, registerData, new Callback(){
#Override
public void onFailure(Call call, IOException e) {
}
#Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
String resp = response.body().string();
if (resp != null) {
Log.d("Statuscode", String.valueOf(response.code()));
Log.d("Body", response.body().string());
}
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
});
Everytime I start the app it crashes when I click the Register-Button caused by a FATAL EXPECTION 'android.os.NetworkOnMainThreadException'
I´ve alread read something about the AsyncTask but I don´t know exactly how to do this.
Try my code below
MediaType JSON = MediaType.parse("application/json; charset=utf-8");
Map<String, String> params = new HashMap<String, String>();
params.put("msisdn", "123123");
params.put("name", "your name");
JSONObject parameter = new JSONObject(param);
OkHttpClient client = new OkHttpClient();
RequestBody body = RequestBody.create(JSON, parameter.toString());
Request request = new Request.Builder()
.url(url)
.post(body)
.addHeader("content-type", "application/json; charset=utf-8")
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
Log.e("response", call.request().body().toString());
}
#Override
public void onResponse(Call call, Response response) throws IOException {
Log.e("response", response.body().string());
}
});
It's because you are trying to execute the HTTP query on the main thread (or UI thread). You shouldn't do a long task on the main thread because your app will hang, because the drawing routines are executed in that thread (hence his another name "UI Thread"). You should use another thread to make your request. For example:
new Thread(){
//Call your post method here.
}.start();
The Android asynctask is a simple class to do asynchronous work. It executes first his "onPreExecute" method on the calling thread, then his "doInBackground" method on a background thread, then his "onPostExecute" method back in the calling thread.
Try using Retrofit library for making Post request to the server. This provides a fast and reliable connection to the server.
You can also use Volley library for the same.

How to get response body in okhttp when code is 401?

I am using OkHttp 3.2.0 and here is code for building request object:
MediaType JSON = MediaType.parse(AppConstants.CONTENT_TYPE_VALUE_JSON);
RequestBody body = RequestBody.create(JSON, requestBody);
HttpUrl url = new HttpUrl.Builder()
.scheme("http")
.host("192.168.0.104")
.port(8080)
.addPathSegment("mutterfly-server")
.addPathSegment("j_spring_security_check")
.addQueryParameter("j_username", jsonObject.getString("emailId"))
.addQueryParameter("j_password", jsonObject.getString("password"))
.build();
request = new Request.Builder()
.addHeader(AppConstants.CONTENT_TYPE_LABEL, AppConstants.CONTENT_TYPE_VALUE_JSON)
.addHeader(AppConstants.ACCEPT_LABEL, AppConstants.CONTENT_TYPE_VALUE_JSON)
.url(url)
.post(body)
.build();
And here is how I parse the response:
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
}
#Override
public void onResponse(Call call, final Response response) throws IOException {
String respBody;
if (response.isSuccessful()) {
if (response.body() != null) {
respBody = response.body().string();
Log.i(TAG, respBody);
response.body().close();
if (AppMethods.checkIfNull(loginParserListener)) {
try {
final VUser user = AppMethods.getGsonInstance().fromJson(respBody, VUser.class);
} catch (Exception e) {
}
}
}
} else {
switch (response.code()){
case 401:
String body="HTTP_UNAUTHORIZED";
break;
}
}
}
});
This is the ideal response(from web rest client) when authentication is failed.
{"msgDesc":"The username or password you entered is incorrect..","statusCode":401}
EDIT:
response.toString() returns
Response{protocol=http/1.1, code=401, message=Unauthorized, url=http://192.168.0.104:8080/mutterfly-server/j_spring_security_check?j_username=s#s.s&j_password=1}
response.body().toString() returns
okhttp3.internal.http.RealResponseBody#528ae030
I want to fetch the msgDesc which is in response body. Is there any method which will return this string?
Try this:
switch (response.code()){
case 401:
JsonObject object=new JsonObject(response.body().string());
String body=object.getString("msgDesc");
break;
}
It's quite weird but Square, the company behind OkHttp, has chosen to not use 'toString()' but 'string()' as method for getting the body as a String.
So this works;
String string = response.body().string();
//convert to JSON and get your value
But this doesn't:
String string = response.body().toString();
401 means permission denied.
Check if your token is valid or user/password is correct.

Retrofit 2 - null response body

I am trying to convert following response with Retrofit 2
{
"errorNumber":4,
"status":0,
"message":"G\u00f6nderilen de\u011ferler kontrol edilmeli",
"validate":[
"Daha \u00f6nceden bu email ile kay\u0131t olunmu\u015f. L\u00fctfen giri\u015f yapmay\u0131 deneyiniz."
]
}
But I am allways getting null response in onResponse method. So I tried to look at error body of the response with response.errorBody.string(). Error body contains exactly same content with raw response.
Here is my service method, Retrofit object and response data declerations:
#FormUrlEncoded
#POST("/Register")
#Headers("Content-Type: application/x-www-form-urlencoded")
Call<RegisterResponse> register(
#Field("fullName") String fullName,
#Field("email") String email,
#Field("password") String password);
public class RegisterResponse {
public int status;
public String message;
public int errorNumber;
public List<String> validate;
}
OkHttpClient client = new OkHttpClient();
client.interceptors().add(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Response response = chain.proceed(chain.request());
final String content = UtilityMethods.convertResponseToString(response);
Log.d(TAG, lastCalledMethodName + " - " + content);
return response.newBuilder().body(ResponseBody.create(response.body().contentType(), content)).build();
}
});
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
domainSearchWebServices = retrofit.create(DomainSearchWebServices.class);
I have controlled response JSON with jsonschema2pojo to see if I modled my response class wright and it seems OK.
Why Retrofit fails to convert my response?
UPDATE
For now as a work around I am building my response from error body.
I have solved the problem. When I make a bad request (HTTP 400) Retrofit doesn't convert the response. In this case you can access the raw response with response.errorBody.string(). After that you can create a new Gson and convert it manually:
if (response.code() == 400 ) {
Log.d(TAG, "onResponse - Status : " + response.code());
Gson gson = new Gson();
TypeAdapter<RegisterResponse> adapter = gson.getAdapter(RegisterResponse.class);
try {
if (response.errorBody() != null)
registerResponse =
adapter.fromJson(
response.errorBody().string());
} catch (IOException e) {
e.printStackTrace();
}
}

Categories

Resources