Can't send volley post request from android phone - android-studio

I'm using Volley to send an http post request with parameters from my android app to my local server running in http://192.168.1.4:3000/battery_signal_report
I'm pretty sure the server is running properly (I checked it with Postman successfully).
also, I successfully sent the request through Android Studio's Emulator using ip 10.0.2.2
Trying to make it work, i used various request implementations including JsonObjectRequest, StringRequest and the custom request described here: Volley JsonObjectRequest Post request not working
Also, I've read somewhere that Volley post requests have some problems with the request header, so i tried to override it in different ways.
Nothing works. onErrorResponse is called every time with an empty VolleyError input.
I've fairly new to android development, so any insights would be much appreciated.
Thanks in advance.

For anyone else coming across this, you need to forget about the header override and setup your own getBodyContentType() and getBody() methods. Follow this pattern:
StringRequest stringRequest = new StringRequest(Request.Method.POST, url, successListener, errorListener) {
#Override
public String getBodyContentType() {
return "application/json; charset=utf-8";//set here instead
}
#Override
public byte[] getBody() {
try {
Map<String, String> params = yourObject.getMappedParams();
JSONObject json = new JSONObject(params);
String requestBody = json.toString();
return requestBody == null ? null : requestBody.getBytes("utf-8");
} catch (UnsupportedEncodingException uee) {
return null;
}
}
};

Related

Problem with Post json data on flask server

i'm setting up a flask server and i would like to do HTTP POST request with a json content-type from android application.
for my purpose i only need to get json data from different client.
one of these client is an android application and it basically do an http post in the server.
the code of android post request is :
public void SendHttp(View view){
new Thread(new Runnable() {
#Override
public void run() {
StringBuffer stringBuffer = new StringBuffer("");
BufferedReader bufferedReader = null;
final String lte_url="http://192.168.1.8:5000/data_center/lte";
HttpPost httpPost = new HttpPost();
try {
HttpClient httpClient = new DefaultHttpClient();
URI uri = new URI("http://192.168.1.8:5000/data_center/lte");
httpPost.addHeader(new BasicHeader(HTTP.CONTENT_TYPE,"application/json"));
httpPost.setURI(uri);
JSONObject send_ = json_lte;
txtSend.setText(""+send_.toString(2));
StringEntity entity = new StringEntity("{"+
"\"date\":"+"\""+send_.getString("Date")+","+
"\"Ping\":"+send_.getString("Ping")+","+
"\"Download\":"+send_.getString("Download")+","+
"\"Upload\":"+send_.getString("Upload")+","+
"\"Latitude\":"+send_.getString("Latitude")+","+
"\"Longitude\":"+send_.getString("Longitude")+","+
"\"Type\":"+send_.getString("Type")+","+
"\"RsRq\":"+send_.getString("RsRq")+","+
"\"RsRp\":"+send_.getString("RsRp")+","+
"\"SINR\":"+send_.getString("SINR")+","+
"\"Bandwidth\":"+send_.getString("Bandwidth")+
"}");
txtSend.setText(entity.toString());
httpPost.setEntity(entity);
HttpResponse httpResponse = httpClient.execute(httpPost);
} catch (some Exeption...)}
}
}).start();
the only output of the flask server is it
Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
192.168.1.237 - - [23/Jul/2019 22:47:58] "POST /data_center/lte HTTP/1.1" 201 -
the code about the server is :
#app.route('/data_center/lte',methods=['POST'])
def post_LTE_data():
try:
data = request.get_json(force=True)
packet = {
'date': data['Date'],
'ping': data['Ping'],
'download': data['Download'],
'upload': data['Upload'],
'latitude': data['Latitude'],
'longitude': data['Longitude'],
'type': data['Type'],
'RsRq': data['RsRq'],
'RsRp': data['RsRp'],
'SINR': data['SINR'],
'bandwidth': data['Bandwidth']
}
lte.append(packet)
return f"OK", 200
except Exception or JsonError as exc:
print(str(exc))
return "some problem"+str(exc), 201
It seems that you have to configure your logging module. You can replace the Python code print(str(exc)) with app.logger.error(str(exc)) to see if it produces some output. You can click here to find some useful code.
By the way, you can take a look at the content received by your Android client because it should receive the response "some problem"+str(exc).
I do not know much about Android code, but it seems that you are dealing with a wrong JSON string. The right format is as below:
{
"foo":"bar",
"good":"bad"
}
In your Android code, you might have to replace
"\"date\":"+"\""+send_.getString("Date")+","
to
"\"date\":"+"\""+send_.getString("Date")+"\","
The above rule should be applied to all lines in the JSON string. Be careful about the symbol "", and you have to make sure that the data during POST is a valid JSON string. Also, I suggest you use another way like utilizing some libraries to build JSON strings to avoid typos.

Accept x-www-form-urlencoded in Web API .NET Core

I have a .NET Core Web API that is returning a 415 Unsupported Media Error when I try to post some data to it that includes some json. Here's part of what is returned in the Chrome Debugger:
Request URL:http://localhost:51608/api/trackAllInOne/set
Request Method:POST
Status Code:415 Unsupported Media Type
Accept:text/javascript, text/html, application/xml, text/xml, */*
Content-Type:application/x-www-form-urlencoded
action:finish
currentSco:CSharp-SSLA:__How_It_Works_SCO
data:{"status":"incomplete","score":""}
activityId:13
studentId:1
timestamp:1519864867900
I think this has to do with my controller not accepting application/x-www-form-urlencoded data - but I'm not sure. I've tried decorating my controler with Consumes but that does not seem to work.
[HttpPost]
[Route("api/trackAllInOne/set")]
[Consumes("application/x-www-form-urlencoded")]
public IActionResult Post([FromBody] PlayerPackage playerPackage)
{ etc..}
Any help greatly appreciated.
The following code worked fine in .NET 4.6.1 and I am able to capture and process the posts shown above.
[ResponseType(typeof(PlayerPackage))]
public async Task<IHttpActionResult> PostLearningRecord(PlayerPackage playerPackage)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var id = Convert.ToInt32(playerPackage.ActivityId);
var learningRecord = await _context.LearningRecords.FindAsync(id);
if (learningRecord == null)
return NotFound();
etc...
Try using [FromForm] instead of [FromBody].
public IActionResult Post([FromForm] PlayerPackage playerPackage)
FromBody > Bind from JSON
FromForm > Bind from Form parameters
You can also remove [FromBody] altogether and trial it then. Because you are expecting form-urlencoded should tell it to bind to object.
For PlayerPackage, the request should send a PlayerPackage Json Object, based on your description, you could not control the request which is posted from other place.
For the request, its type is application/x-www-form-urlencoded, it will send data with {"status":"incomplete","score":""} in string Format instead of Json object. If you want to accept {"status":"incomplete","score":""}, I suggest you change the method like below, and then convert the string to Object by Newtonsoft.Json
[HttpPost]
[Route("~/api/trackAllInOne/set")]
[Consumes("application/x-www-form-urlencoded")]
public IActionResult Post([FromForm] string data)
{
PlayerPackage playerPackage = JsonConvert.DeserializeObject<PlayerPackage>(data);
return Json(data);
}
This did the trick for me:
[HttpPost]
[Consumes("application/x-www-form-urlencoded")]
public IActionResult Post([FromForm]IFormCollection value)
I had the same problem. FormDataCollection has no default constructors which is required by Formatters. Use IFormCollection instead.
Can make setting like as
[HttpPost()]/[HttpGet()]
[Consumes("application/x-www-form-urlencoded")]
public async Task<IActionResult> MethodName([FromForm] IFormCollection value)
don't forget to add [FromForm]

Dotnet Core 2.0.3 Migration | Encoding unable to translate bytes [8B]

Im not sure if this should just go direct to the github but I thought id check here first if anyone has encountered this issue before.
I recently have upgraded one of my apps to use dot net 2.0.3 From 1.1.4.
Everything works fine locally but when I deploy to my app service in azure I get the following exception.
System.Text.DecoderFallbackException: Unable to translate bytes [8B] at index 1 from specified code page to Unicode.
The code that calls it is a httpclient that talks between the apps.
public async Task<T1> Get<T1>(string url, Dictionary<string, string> urlParameters = null) where T1 : DefaultResponse, new()
{
var authToken = _contextAccessor.HttpContext.Request.Cookies["authToken"];
using (var client = new HttpClient().AcceptJson().Acceptgzip().AddAuthToken(authToken))
{
var apiResponse = await client.GetAsync(CreateRequest(url, urlParameters));
T1 output;
if (apiResponse.IsSuccessStatusCode)
{
output = await apiResponse.Content.ReadAsAsync<T1>();
//output.Succeeded = true;
}
else
{
output = new T1();
var errorData = GlobalNonSuccessResponseHandler.Handle(apiResponse);
output.Succeeded = false;
output.Messages.Add(errorData);
}
return output;
}
}
public static HttpClient AcceptJson(this HttpClient client)
{
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
return client;
}
public static HttpClient Acceptgzip(this HttpClient client)
{
// Commenting this out fixes the issue.
//client.DefaultRequestHeaders.AcceptEncoding.Add(StringWithQualityHeaderValue.Parse("gzip"));
client.DefaultRequestHeaders.AcceptEncoding.Add(StringWithQualityHeaderValue.Parse("deflate"));
return client;
}
public static HttpClient AddAuthToken(this HttpClient client, string authToken)
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authToken);
return client;
}
Im a bit stumped as to whats going on.
So I have 2 apps which we call client and server from now on.
Client uses the above code to talk to the server.
Locally this is fine on azure not so, this all worked fine before upgrading.
So I setup the client locally to talk to the server on azure I was able to replicate the issue.
I had a look at the response in fiddler and it is able to correctly decode it.
If anyone has any idea where I should look and has seen it before any info would be great :D.
UPDATE 1
So after some more digging I decided to remove gzip and then everything started working.
client.DefaultRequestHeaders.AcceptEncoding.Add(StringWithQualityHeaderValue.Parse("gzip"));
Can anyone explain this?
8B can be a second byte of multi-byte UTF8 character. The DecoderFallbackException tells that you’re interpreting the data as some other encoding. Probably Latin-1 which doesn’t have 8B character.
In fiddler, you should look at the content-type HTTP header in the response. If it says application/json or application/json; charset=utf-8, it’s probably a bug in .NET, because even without charset=utf-8 RFC 4627 says the default encoding is already UTF-8.
If it says something else, I would try changing the server so it sends the correct content-type header in the response.

OkHttp CookieJar saveFromResponse method

I created a simple project which using CookieJar. Now I am trying to understand when saveFromResponse method works. But I see in my logs that loadForRequest works fine, but I doesn't see saveFromResponse logs. Why? At what time of process this method works? Can we use only intercept method if we works with cookies or may be we have a special situation for using CookieJar?
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new ReceivedCookiesInterceptor())
.cookieJar(new CookieJar() {
private final HashMap<HttpUrl, List<Cookie>> cookieStore = new HashMap<>();
#Override
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
Log.d(TAG,"saveFromResponse");
cookieStore.put(url, cookies);
}
#Override
public List<Cookie> loadForRequest(HttpUrl url) {
Log.d(TAG,"loadForRequest");
List<Cookie> cookies = cookieStore.get(url);
return cookies != null ? cookies : new ArrayList<Cookie>();
}
})
.build();
Request request = new Request.Builder()
.url("http://www.publicobject.com/helloworld.txt")
.build();
Response response = client.newCall(request).execute();
response.body().close();
I know it's a bit late, but I was struggling with the exact same issue and then I realised that saveFromResponse is only called on new cookies. This means that all the cookies you set on loadForRequest are not received in saveFromResponse.
That's the behaviour I could infer, but I'm not sure if it is the one that it should be, as this way you can't get cookie value updates from remote server.
Did you experienced the behaviour that only on the first request after OkHttpClient creation the cookies are received and not on the rest of the requests?
Please, someone with more knowledge that can shed some light?

text integrating api.ai into android

I'm trying to integrate api.ai with android. I have followed the steps required for that. I require integrating text instead of speech. I want to receive the text as input from the user and display it. Can anyone please suggest me the solution for this?
Step 1:Create Configuration for API AI
final AIConfiguration config = new AIConfiguration("<Client access token>",
AIConfiguration.SupportedLanguages.English,
AIConfiguration.RecognitionEngine.System);
aiService = AIService.getService(this, config);
aiService.setListener(this);
aiDataService = new AIDataService(config);
aiRequest = new AIRequest();
Step 2:Set your text here
aiRequest.setQuery(message);
Step 3:Get your response from API AI using AsyncTask
new AsyncTask<AIRequest,Void,AIResponse>(){
#Override
protected AIResponse doInBackground(AIRequest... aiRequests) {
final AIRequest request = aiRequests[0];
try {
final AIResponse response = aiDataService.request(aiRequest);
return response;
} catch (AIServiceException e) {
}
return null;
}
#Override
protected void onPostExecute(AIResponse response) {
if (response != null) {
Result result = response.getResult();
String reply = result.getFulfillment().getSpeech();
sendMessage(message);
mimicOtherMessage(reply);
mListView.setSelection(mAdapter.getCount() - 1);
}
}
}.execute(aiRequest);
If I understand right -- you do not need the Voice input for your Android application and simply want the user to type in the text in their Android application. Post that, you are expecting to pass on that request to API.AI for further processing and a possible response.
If the above is correct, then you do not need any of the Voice capability Activities. Simply take it in the text from the User and pass that on to the API.AI HTTP API.

Resources