I have to send/post some data to .svc Web Service that basically connect to remote database. I'm using JSONStringer to send the data but every time response status is false. My data is not sent. How to use HttpPost in Android . Can someone help me how to solve this .
Here is my webservice code
String namespace = "http://103.24.4.60/xxxxx/MobileService.svc";
public void ActivityUpload( final String strCurrentDateTime, final String strTitle, final String replaceDescChar, final String editedHashTag)
{
new AsyncTask<String, Void, String>()
{
#Override
protected String doInBackground(String... arg0)
{
String line = "";
try
{
Log.e("ActionDate "," = "+ strCurrentDateTime);
Log.e("ActivityId"," = "+strActivityId);
Log.e("UserId"," = "+str_UserId);
Log.e("ObjectId"," = "+strVessId);
Log.e("Name"," = "+strTitle);
Log.e("Remark"," = "+replaceDescChar);
Log.e("Status"," = "+"PENDING");
Log.e("Type"," = "+strType);
Log.e("starflag"," = "+0);
Log.e("HashTag"," = "+editedHashTag);
Log.e("Authentication_Token"," = "+str_Authentication_Token);
// make web service connection
HttpPost request = new HttpPost(namespace + "/Upd_Post_Activity");
request.setHeader("Accept", "application/json");
request.setHeader("Content-type", "application/json");
// Build JSON string
JSONStringer TestApp = new JSONStringer().object()
.key("ActionDate").value(strCurrentDateTime)
.key("ActivityId").value(strActivityId)
.key("UserId").value(str_UserId)
.key("ObjectId").value(strVessId)
.key("Name").value(strTitle)
.key("Remark").value(replaceDescChar)
.key("Status").value("PENDING")
.key("Type").value(strType)
.key("starflag").value("0")
.key("HashTag").value(editedHashTag)
.key("Authentication_Token").value(str_Authentication_Token).endObject();
StringEntity entity = new StringEntity(TestApp.toString());
Log.d("****Parameter Input****", "Testing:" + TestApp);
request.setEntity(entity);
// Send request to WCF service
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpResponse response = httpClient.execute(request);
Log.d("WebInvoke", "Saving: " + response.getStatusLine().toString());
// Get the status of web service
BufferedReader rd = new BufferedReader(new InputStreamReader(
response.getEntity().getContent()));
// print status in log
while ((line = rd.readLine()) != null) {
Log.d("****Status Line***", "Webservice: " + line);
}
} catch (Exception e) {
e.printStackTrace();
}
return line;
}
}.execute();
}
Here is input Parameter.
****Parameter Input****﹕ Testing:{"ActionDate":"2016-01-21%2014:20:43%20PM","ActivityId":"120160119180421058","UserId":"125","ObjectId":"1","Name":"Title2","Remark":"Test%20two","Status":"PENDING","Type":"3","starflag":"0","HashTag":"990075","Authentication_Token":"6321D079-5B28-4F3F-AEE7-D59A1B9EFA59"}
Thanks in advanced.
realize android httpclients are in process of deprecation ( in favor of httpsurlconnection ) but, these httpclients are still used pretty widely. On gradle builds, regard the deprication, and with small dependency lib tweeks , httpclient may be used for some time still.
( still gonna use httpclient ? )
Put android aside for a min.
learn how to CURL with JSON body for tests that show you what you EXACT JSON in body and exact HEADERS you will need to get success http result to a post ... ref here
Once you have that you can then go about transferring your curl test's components over to android.httpclient.exec.POST using httpclient of your choice.
Set the same group of Headers you had over in curl tests in your android post. apache.httpclient sample
2.a. make sure that default list of headers from the clients 'request' constructor does NOT include by default some headers you DO NOT want... In order to assure of this ,you probably will need to turn on HEADER logging for your client.... java example logger . remove unnecessary headers included by the framework constructor of POST.
2.b android logger (WIRE, HEADERS) is diff from and may take some digging , depend on what client is in use.
with the same headers as curl tests, set the http.posts request.entity to either a string or a properly encoded array of bytes containing the same JSON body used in the curl tests.
3.A. depending on the JSON lib, create your message objects and then convert the objects to some friendly type for enclosure in an entity for the post ie use a 'writer' to convert objects to a serialized string with the JSON.
reqRole = new ObjectMapper().createObjectNode();
reqRole.put("__type", "Pointer");
reqRole.put("className", "_Role");
reqRole.put("objectId", roleId);
rootOb.put("requestedRole", reqRole);
rootOb.put("requestedBy",usersArr);
StringWriter writer = new StringWriter();
try {
new ObjectMapper().writeValue(writer, rootOb)
..
String http-post-str=writer.toString();
3.B. wrap the string with json in the POST request...
httpPost.setEntity(new StringEntityHC4(http-post-str));
exec the request and youll get the same results you got in curl because the headers are same or nearly same and the body is the same , encoded string of json. same input = same result
Related
I am developing an android app where user logs on to his/her account. After logging in I will receive XSRF token and Laravel Session Id to recognise the specific user. I have to send these tokens for every request I send to the API's to get the appropriate information. But when I am sending the required details as shown in the image, I am getting HTMl file as response instead of getting JSON Object. I was seriously stuck at this problem. Correct Solution may take forward the whole app.
class RegisterConnection extends AsyncTask<String,String,JSONObject> {
protected JSONObject doInBackground(String... arg0) {
JSONObject output = new JSONObject();
DefaultHttpClient client = new DefaultHttpClient();
HttpConnectionParams.setConnectionTimeout(client.getParams(), 5000); //Timeout Limit
HttpResponse response = null;
try {
HttpGet get = new HttpGet(statsURL);
get.setHeader("Accept", "application/json");
CookieStore store = new BasicCookieStore();
BasicClientCookie cookie1 = new BasicClientCookie("XSRF-TOKEN", XSRF);
BasicClientCookie cookie2 = new BasicClientCookie("laravel_session", laravel);
store.addCookie(cookie1);
store.addCookie(cookie2);
client.setCookieStore(store);
response = client.execute(get);
if(response!=null){
InputStream in = response.getEntity().getContent();
String resultstring = Utilities.convertStreamToString(in);
Log.i("Result1", resultstring);
output = new JSONObject(resultstring);
Log.i("Result2", output.toString());
}
} catch(Exception e) {
e.printStackTrace();
try {
output.put("sai","error");
Log.i("MainActivity", output.toString());
} catch (JSONException e1) {
e1.printStackTrace();
}
return output;
}
return output;
}
These are the server requirements
http://imgur.com/OY9Q673
This is the Output received
http://imgur.com/IB5AEcT
As far as I can tell, there is nothing wrong with your Android client code.
You are getting HTML from the server so the main reason could be that your Laravel server is rendering the views and sending you back html instead of JSON. Instead of rendering the views on the server, you should send JSON response on your Laravel server side.
Add Jsoup dependency in your gradle file
implementation 'org.jsoup:jsoup:1.11.2'
Document document = Jsoup.parse("http://imgur.com/IB5AEcT");
Elements el = doc.select("button");
Log.i("..........",""+el.attr("data-invite-details"));
Jsoup tutorial
http://jsoup.org/apidocs/org/jsoup/Jsoup.html
I've got an Android project that allows me to log-in with Google-accounts. Everything works as it's supposed to and I'm able to retrieve the Person's (com.google.android.gsm.model.people.Person) data, like Google email, username, profile picture url, etc.
I also have a Web API hosted online. In this Web API I can get a JSON-list of products by using the following: mywebhost/api/products.
Obviously these GET-requests are Authorized by OAuth 2.0, meaning I have to log-in with a Google Account on the mywebhost/Account/Login page to be authorized to get the JSON-list from the Web API. (When I'm not logged in, I receive the following JSON-list: {"$id":"1","Message":"Authorization has been denied for this request."})
I know how to send POST-requests in Android. For example with the code:
public class TaskPostAPI extends AsyncTask<String, Void, String>
{
GoogleApiClient googleAPI;
public TaskPostAPI(GoogleApiClient googleAPI){
this.googleAPI = googleAPI;
}
#Override
protected String doInBackground(String... urls){
String response = "";
for(String url : urls){
DefaultHttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(url);
try{
List<NameValuePair> nvPairs = new ArrayList<NameValuePair>(3);
//nvPairs.add(new BasicNameValuePair("personName", Plus.PeopleApi.getCurrentPerson(googleAPI).getDisplayName()));
//nvPairs.add(new BasicNameValuePair("personGooglePlusProfile", Plus.PeopleApi.getCurrentPerson(googleAPI).getUrl()));
//nvPairs.add(new BasicNameValuePair("personEmail", Plus.AccountApi.getAccountName(googleAPI)));
// TODO: Use the correct nvPairs to be able to Log-in with the Google-account
post.setEntity(new UrlEncodedFormEntity(nvPairs));
HttpResponse execute = client.execute(post);
InputStream content = execute.getEntity().getContent();
BufferedReader buffer = new BufferedReader(new InputStreamReader(content));
String s = "";
while((s = buffer.readLine()) != null)
response += s;
}
catch(Exception ex){
ex.printStackTrace();
}
}
return response;
}
#Override
protected void onPostExecute(String result){
// Do nothing yet
}
}
So, now the question:
In the code sample above, what should the nvPairs be to be able to successfully log-in with a Google-account. Or should I use something completely different than normal HttpPost to log-in with a Google-account on my Web API?
Also: The url provided is the default Log-in page. On this page I have three different options to log-in. Since we only want to use the Google log-in, how can I retrieve the url of the Google Log-in button from the Web API Login-page to use for the POST-request?
2b. With the second question: What Plug-in I could use in FireFox to see the links I'm redirected to? So I know which Login-url I should use instead of the default Login-page.
Thanks in advance for the responses.
Edit 1: I've tried a different approach, but I'm not sure it will work for the HttpGet-requests. What I've tried is opening a WebView with the Log-in page, and after I reach the page where I come when I successfully logged-in, I close the WebView.
However, when I use the HttpGet-requests, I still get the Unauthorized JSON back, so how can I use this WebView Log-in to make the HttpGet-request "believe" I'm logged-in and Authorized?
If someone still has an idea using the first approach (HttpPost-request), or if someone has a completely different approach, let me know.
Ok, I've found the POST I can use in the C# web project (/POST/ExternalLogin). There I also see what I should send:
In the header:
Content-Type application/x-www-form-urlencoded
Cookie with __RequestVerificationToken
In the body:
provider ("Google")
returnUrl
__RequestVerificationToken
The second __RequestVerificationToken needs to be a different one than the one used in the Cookie, but after decrypting it in the C# Web API it should be the same. This is the only problem I have right now, but I've got a different stackoverflow question for that.
For the full code:
public class TaskPostAPI extends AsyncTask<String, Void, String>
{
private String TOKEN = "__RequestVerificationToken";
#Override
protected String doInBackground(String... urls){
String response = "";
for(String url : urls){
HttpPost post = new HttpPost(url);
try{
// Add the default Content-type to the Header
post.addHeader("Content-type", "application/x-www-form-urlencoded");
// Get the baseUrl from the given url
URL u = new URL(url);
String baseUrl = u.getProtocol() + "://" + u.getHost();
// POST-request requires anti-forgery Cookie
// Get all Cookies
CookieManager cookieManager = CookieManager.getInstance();
String cookie = cookieManager.getCookie(baseUrl);
String[] cookies = cookie.split(";");
// Put all Cookies in a HashMap with cookieKey & cookieToken
HashMap<String, String> cookieStrings = new HashMap<String, String>();
for(String cook : cookies){
String[] cs = cook.split("=");
cookieStrings.put(cs[0], cs[1]);
}
// Add the Cookie to the Header
post.addHeader("Cookie", TOKEN + "=" + cookieStrings.get(TOKEN) + "");
// POST-request requires cookieToken, provider and returnUrl
List<NameValuePair> nvPairs = new ArrayList<NameValuePair>(3);
nvPairs.add(new BasicNameValuePair(TOKEN, cookieStrings.get(TOKEN)));
nvPairs.add(new BasicNameValuePair("provider", "Google"));
nvPairs.add(new BasicNameValuePair("returnUrl", baseUrl));
post.setEntity(new UrlEncodedFormEntity(nvPairs));
Log.i("COOKIE OUTPUT", TOKEN + "=" + cookieStrings.get(TOKEN) + "");
// Send the POST-request
HttpResponse execute = MainActivity.HttpClient.execute(post);
// Get the response of the POST-request
InputStream content = execute.getEntity().getContent();
BufferedReader buffer = new BufferedReader(new InputStreamReader(content));
String s = "";
while((s = buffer.readLine()) != null)
response += s;
}
catch(Exception ex){
ex.printStackTrace();
}
}
return response;
}
In this piece of code the following line is incorrect and still needs fixing:
nvPairs.add(new BasicNameValuePair(TOKEN, cookieStrings.get(TOKEN)));
cookieStrings.get(TOKEN) need to be replaced with the correct token to send.
I am trying to get an android app to interact with a server in Django.
The app is trying to POST "json" data to Django. However, I am unable to receive the object on the Django end.
The value of request.POST is <QueryDict: {}> although the data sent isn't blank. Following is the code snippet for POST request from android.
public static String POST(String url,JSONObject obj){
InputStream inputStream = null;
String result = "";
try{
HttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url);
String json = obj.toString();
StringEntity se = new StringEntity(json);
httpPost.setEntity(se);
httpPost.setHeader("Accept", "application/json");
httpPost.setHeader("Content-type","application/json");
HttpResponse httpResponse = httpClient.execute((HttpUriRequest)httpPost);
inputStream = httpResponse.getEntity().getContent();
if(inputStream!=null){
result = convertInputStreamToString(inputStream);
}else{
result = "Did not work!";
}
}catch(Exception e){
}
return result;
}
EDIT:
Earlier, I was getting CSRF error and handled it this way (I haven't worked with Django enough to know if this is correct way to handle CSRF error)
#csrf_exempt
def search(request):
logger.debug(request.POST)
"""Code for JSON object processing"""
Any help with rectifying the problem would be highly appreciated.
OK I'm not very fluent in java but it seems to me that your request is well formed.
I think the issue is that you are sending the data as a json string instead of as if it was a raw form. When you do it this way, the data is not displayed in request.POST but in request.body as what it is: a json string, not form-like data.
So I think you have to take one of these ways:
send the data from the Android app as a form (not json-like). This way you'll see it in request.POST or
translate request.body into a dict and work with it instead of request.POST
Hope this helps! :)
It has been a while since I programmed for Android and I have lost all my previous work which had the code in it I am having problems with. I am developing an app for both Android and iPhone which connect to the same server to download data. All is well in the iPhone version but on Android when I hit the server with the post data containing the method name I would like to to run on the server it seems that the data is not added to the request.
Why is the POST not working in this request for Android but does for the iPhone version of the app?
Here is the code I am using:
public static void makeRequest() throws Exception {
Thread t = new Thread() {
public void run() {
Looper.prepare(); //For Preparing Message Pool for the child Thread
HttpClient client = new DefaultHttpClient();
HttpConnectionParams.setConnectionTimeout(client.getParams(), 10000);
HttpResponse response;
HttpEntity entity;
JSONObject json = new JSONObject();
try {
HttpPost post = new HttpPost("http://divisi.co.uk/rest/requesthandler.php");
json.put("method", "getEventListData");
StringEntity se = new StringEntity(json.toString());
se.setContentType(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));
post.setEntity(se);
response = client.execute(post);
entity = response.getEntity();
String retSrc = EntityUtils.toString(entity);
JSONObject result = new JSONObject(retSrc); //Convert String to JSON Object
if(result.getString("SC") == "200"){
JSONArray data = result.getJSONArray("data");
}
else{
}
} catch(Exception e) {
e.printStackTrace();
}
Looper.loop(); //Loop in the message queue
}
};
t.start();
}
The response I get mack from the server is:
{"data":{"scalar":""},"SC":405,"timestamp":1363788265}
Meaning the method name was not found, i.e. not posted in my request to the server.
heres an example of how i do things like this:
HttpClient httpClient = new DefaultHttpClient();
HttpPost postRequest = new HttpPost("http://divisi.co.uk/rest/requesthandler.php");
MultipartEntity reqEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
reqEntity.addPart(new FormBodyPart("method", new StringBody("getEventListData")));
reqEntity.addPart(new FormBodyPart("NEED_A_KEY_HERE", new StringBody("" + json.toString())));
postRequest.setEntity(reqEntity);
HttpResponse response = httpClient.execute(postRequest);
JSONObject responseDict = new JSONObject(EntityUtils.toString(response.getEntity()));
allow this is your "http://divisi.co.uk/rest/requesthandler.php" page code, then in android you can use this... you don't allow post in your URL,
use fiddler on your sever side. see if the http message is correct. it seems your sever side problem, can you show us your sever side code which receive and parse json.
If the server can't read your request try to remove:
se.setContentType(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));
It will use the mime type defaults HTTP.PLAIN_TEXT_TYPE i.e. "text/plain".
I don't see any other possibility, if your code is the one you posted and not a more complicated input JSON object.
Your code to set the POST body may be just fine. I think the problem may be with your web service. Try using something like Rested or curl to manually make the call to your server. I made exactly the same request you are making, including with and without the POST body, and I got the same response from your server:
{"data":{"scalar":""},"SC":405,"timestamp":1365704082}
Some things that may be tripping you up:
JSONObject result = new JSONObject(retSrc); //Convert String to JSON Object
if(result.getString("SC") == "200"){
JSONArray data = result.getJSONArray("data");
}
Here, you are comparing the string "405" to "200" using ==, when you should first do a null check and then use .equals("200") instead. Or, use result.getInt("SC") == 200 since this is an integer type in your response JSON.
Also, the "data" entity from your server response is not actually coming back as a JSON array. You should use getJSONObject("data") instead.
Additionally, it's always a good idea to externalize your strings.
Here's how the code should look:
public static final String JSON_KEY_SC = "SC";
public static final String JSON_KEY_DATA = "data";
...
JSONObject result = new JSONObject(retSrc); //Convert String to JSON Object
String sc = result.getString(JSON_KEY_SC);
if (sc != null && sc.equals("200")) {
JSONObject data = result.getJSONObject(JSON_KEY_DATA);
}
else {
...
}
Okay, so I was trying to send Http Post Requests to this one site, and I sniffed the sent request with wireshark thus getting the text data from the post request of this site. I used this in a stock Java application, and it worked perfectly fine. I could use the post method regularly with no problem whatsoever, and it would return the appropriate website. Then I tried doing this with Android. Instead of returning the actual html data after executing the post request, it returns the regular page html data untouched. It DOES send a post request (sniff with wireshark again), it just doesn't seem to get the appropriate response. I took the exact same method used from another one of my projects, which worked perfectly fine in that project, and pasted it into my new project. I added the INTERNET user permission in Android, so there's nothing wrong with that. The only visible difference is that I used NameValuePairs in the other one (the one that worked) and in this one I'm directly putting the string into a StringEntity without encoding (using UTF-8 encoding screws up the String though). I used this exact same line of text in regular Java like I said, and it worked fine with no encoding. So what could be the problem? This is the code:
public static String sendNamePostRequest(String urlString) {
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(urlString);
StringBuffer sb = new StringBuffer();
try {
post.setEntity(new StringEntity(
"__EVENTTARGET=&__EVENTARGUMENT=&__VIEWSTATE=%2FwEPDwULLTE3NDM5MzMwMzRkZA%3D%3D&__EVENTVALIDATION=%2FwEWBAL%2B%2B4CfBgK52%2BLYCQK1gpH7BAL0w%2FPHAQ%3D%3D&_nameTextBox=John&_zoekButton=Zoek&numberOfLettersField=3"));
HttpResponse response = client.execute(post);
HttpEntity entity = response.getEntity();
BufferedReader br = new BufferedReader(new InputStreamReader(
entity.getContent()));
String in = "";
while ((in = br.readLine()) != null) {
sb.append(in + "\n");
}
br.close();
} catch (Exception e) {
e.printStackTrace();
}
return sb.toString();
}
Can you see what's wrong here?