I recently came across strange problem when sending / recieving data thru http POST request on Android.
I had difficulties with setting Fiddler to monitor the traffic between my Android app and server so I created simple web form to simulate the POST request.
<form action="http://www.my.server.org/my_script.php" method="POST">
<input name="deviceID" type="text" width=30> Device ID <br>
<input name="lang" type="text" width=30> Language (en / cs) <br>
<input name="lastUpdated" type="text" width=30> Last Updated (yyyy-MM-dd hh:mm) <br>
<button type="submit">Send</button>
</form>
When I send the request using this form, a response is delivered back with 200 OK status code and desired XML file.
I thought it would be equivalent to Java code I have in my Android app.
private static final String POST_PARAM_LAST_UPDATED = "lastUpdated";
private static final String POST_PARAM_DEVICE_ID = "deviceId";
private static final String POST_PARAM_LANG = "lang";
...
// Create a POST Header and add POST Parameters
HttpPost httpPost = new HttpPost(URL_ARTICLES);
List<NameValuePair> postParameters = new ArrayList<NameValuePair>(3);
postParameters.add(new BasicNameValuePair(POST_PARAM_DEVICE_ID, deviceId));
postParameters.add(new BasicNameValuePair(POST_PARAM_LANG, lang));
postParameters.add(new BasicNameValuePair(POST_PARAM_LAST_UPDATED, lastUpdated));
httpPost.setEntity(new UrlEncodedFormEntity(postParameters));
// Create new HttpClient and execute HTTP Post Request
HttpClient httpClient = new DefaultHttpClient();
HttpResponse response = httpClient.execute(httpPost);
// Get and parse the response
List<Article> parsedArticles = new ArrayList<Article>();
HttpEntity entity = response.getEntity();
if (entity != null) {
parsedArticles = Parser.parseArticles(entity.getContent());
}
However even when I put the same parameter values (as those I put in the web form), the response in this case is 204 NO CONTENT and no XML file obviously.
Can somebody here please tell me how come these two methods are not equivalent and the responses are different? Is it something with encoding or what am I missing?
I unfortunately don't have access to the server and I'm not able to debug Android outgoing and incoming data because Fiddler and my emulator / device connected to PC refused to cooperate.
And I also wondered if I should use AndroidHttpClient instead of DefaultHttpClient but I think it's not going to change anything in this case.
Thanks in advance!
Due to Maxims comment I found out what's wrong.
It was one stupid lower case letter in the POST_PARAM_DEVICE_ID constant. It's value was "deviceId" (and should be "deviceID" as in web form).
Well, my fellow developers, pay attention when defining String keys - it's case sensitive!
Related
I'm attempting to send a POST request from within an Android app to my Google App Engine app in order to upload a file to the blobstore and some metadata to the Datastore. I built a regular webform which I can access from a browser, and posting from there works just fine. However, I haven't been able to do the same from my Android app.
A lot of other StackOverflow posts mention the use of MultipartEntity or MultipartEntityBuilder to build the post request. The former seems to be deprecated but there are more examples of it, so I tried both ways (separately, of course):
HttpClient httpClient = new DefaultHttpClient();
HttpPost postRequest = new HttpPost(upload_url);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
builder.addTextBody("poem_name", "Testing poem_name from Android", ContentType.MULTIPART_FORM_DATA);
builder.addTextBody("poem_text", "blah", ContentType.MULTIPART_FORM_DATA);
postRequest.setEntity(builder.build());
HttpResponse response = httpClient.execute(postRequest);
HttpEntity theEntity = response.getEntity();
theEntity.consumeContent();
httpClient.getConnectionManager().shutdown();
and
HttpClient httpClient = new DefaultHttpClient();
HttpPost postRequest = new HttpPost(upload_url);
StringBody poem_name = new StringBody("Testing poem_name from Android");
StringBody poem_text = new StringBody("blah");
MultipartEntity entity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
entity.addPart("poem_name", poem_name);
entity.addPart("poem_text", poem_text);
postRequest.setEntity(entity);
HttpResponse response = httpClient.execute(postRequest);
The original webform, which works like a charm from a regular browser, looks like this in my template (I omitted the file upload initially in the Android code, as that weas too problematic to debug right away):
<form action="{{ upload_url }}" method="POST" enctype="multipart/form-data">
Poem Title: <input name="poem_name" required><br>
Poem Text:<br><textarea name="poem_text" rows="5" cols="40"></textarea><br>
Upload File: <input type="file" name="file"><br>
<input type="submit" name="submit" value="Add Poem">
</form>
However, when I execute either of the top two sections of code on my Android app, nothing shows up on my server. The upload_url that's passed into the HttpPost constructor is the very same one that's used in the action field of the web form {{ upload_url }} (it's dynamically generated by Google App Engine). So, I thought I'd try posting to any web form, not one that requires multipart entities and dynamic URLs. I built a new barebones web form on a different page of the app, like so...
<form action="/testForm" method="post">
<input name="nickname"><br>
<input type="submit" value="Create Test Entity">
</form>
...and attempted a basic post request as seen in numerous beginner examples:
HttpClient httpClient = new DefaultHttpClient();
HttpPost postRequest = new HttpPost("http://my-app-title.appspot.com/testForm");
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(1);
nameValuePairs.add(new BasicNameValuePair("nickname", "test with NameValuePair"));
postRequest.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = httpClient.execute(postRequest);
Sure enough, the form works great in a browser but produces no result when executing this code from my Android app (not even null values in place of the "nickname" field, which tells me that the issue lies in the post request not getting executed for some reason). By all accounts that I've read, this ought to work. Is there something I'm forgetting which isn't allowing me to complete the post request? I'd really appreciate any help.
Per njzk2's suggestion, I used an InputStream to look at the content of the HttpResponse. For reference, this is the code I used:
InputStream iStream = response.getEntity().getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(iStream));
while ((tempString = reader.readLine()) != null) {
postResponseOutput += tempString;
}
Log.d("HttpResponse Output", postResponseOutput);
For the barebones form, I made the mistake of requiring a login on the url at /testForm, so Google's sign-in page was returned rather than my form. Removing that restriction made the form work perfectly.
Trying it with the MultipartEntityBuilder section of my code returned something interesting in the post response, nothing more than "The request's content type is not accepted on this URL". But trying it with the MultipartEntity section seemed to do the trick. The httpresponse returned an internal server error (something to do with user authentication). That explains why posting to the original webform wasn't working - there was a server error preventing the form from being accessed in the first place. I trust that once I resolve the error that the form will work just as well as it did for my testForm.
I am trying to retrieve a JSON file from a web service using the following URL. That works fine when I use a browser to send the HTTP request.
For the Android application I came up with the following code.
// Android request
String url = "http://data.wien.gv.at/daten/geoserver/ows?service=WFS" +
"&request=GetFeature&version=1.1.0&typeName=ogdwien:BAUMOGD" +
"&srsName=EPSG:4326&outputFormat=json" +
"&bbox=16.377681,48.211448,16.379829,48.21341,EPSG:4326" +
"&maxfeatures=10"
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(url);
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
String result = EntityUtils.toString(entity);
Though, EntityUtils does not output a JSON file but this XML exception.
// Value of result
<?xml version="1.0" encoding="UTF-8"?>
<ows:ExceptionReport version="1.0.0"
xsi:schemaLocation="http://www.opengis.net/ows http://data.wien.gv.at/daten/geoserver/schemas/ows/1.0.0/owsExceptionReport.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ows="http://www.opengis.net/ows">
<ows:Exception exceptionCode="NoApplicableCode">
<ows:ExceptionText>java.io.EOFException: input contained no data
input contained no data</ows:ExceptionText>
</ows:Exception>
</ows:ExceptionReport>
I hope you can see what wents wrong ...
The HTML specifications technically define the difference between "GET" and "POST" so that former means that form data is to be encoded (by a browser) into a URL while the latter means that the form data is to appear within a message body. > [source]
Since you do encode the full request into the URL (request=GetFeature etc.) => use HttpGet instead.
Might even work imo with post since the url should still be transmitted to the server but the server would need to detect that the post request is actually a get request and behave accordingly.
I want to get the session cookie of a website. Unfortunately the "Set-Cookie"-Header doesn't show up.
Here's the code I've written:
"commands" is a String[][] and the whole code is wrapped by try/catch.
CookieStore cookieStore = new BasicCookieStore();
HttpContext localContext = new BasicHttpContext();
localContext.setAttribute(ClientContext.COOKIE_STORE,cookieStore);
HttpPost httppost = new HttpPost(url);
List<NameValuePair> nvps = new ArrayList<NameValuePair>(0);
for (int i=0;i<commands.length;++i)
nvps.add(new BasicNameValuePair(commands[i][0],commands[i][1]));
httppost.setEntity(new UrlEncodedFormEntity(nvps,HTTP.UTF_8));
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
Header[] headers = response.getAllHeaders();
List<Cookie> cookies = cookieStore.getCookies();
String data = EntityUtils.toString(entity);
My understanding of Http Communication tells me that there should be a "Set-Cookie" Header. The only Headers I get from response.getAllHeaders() are Connection:close, X-Powered-By:PHP/4.3.4 and Content-Type:text/html
There is a bit of javascript included in the returned data (response.getEntity()).
<script language = "javascript">
<!--
location.href="/index.php";
function SetCookie(name,value,expire,path){
document.cookie = name + "=" + escape(value) + ((path == null) ? "":(";path="+path))
}
var iad = 461180104
SetCookie("iad",iad,0,"/")
-->
</script>
As far as I understand this, this code is never executed because it's just a comment ?!
But as well this is probably the bit where the cookie should be created.
Any ideas?
UPDATE:
"Opera Mobile" is the only browser for Android I found which has no problem with cookies on this site. "Opera Mini", "Dolphin HD" and the Froyo Stock browser all fail. No Desktop browser has problems connecting. Is this a webkit issue? And if this is the case: how to avoid it?
Using Chrome's developer tools or Firebug, check the HTTP response for the "expires" parameter in the Set-Cookie header field. Make sure the time / date settings on the phone are set correctly. If the browser thinks the cookie is already expired, it won't store it.
If that doesn't work try using wireshark / tshark to grab a trace of the communication from your client, and compare it to a browser that's working the way you expect it to.
By the way, the comment delimiters around that bit of Javascript don't prevent the script from being run; they just prevent older (really old) browsers from trying to render the script in the document. That cookie ("iab") doesn't look like the cookie for authentication. There's likely an http-only cookie with a session identifier; you should be able to see it using the aforementioned Firebug / Dev tools.
I want to create an Application, the description of it as follows
Perform search
Display the results.
Basically, I want to create an application for an existing web-site which does this, but my need is to create for a Mobile.
Based on the website link, it refers to some ASP pages. for e.g. http://test.com/query.asp. The website allows the user to enter various input for search.
I want to create and then send the same request to the server and get the result. How can I know what all parameters/headers it is taking and what format is the response (XML or JSON).
Below is my sample code for the Android Device
HttpClient httpclient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url);
List nameValuePairs = new ArrayList(3);
//this is where you add your data to the post method
nameValuePairs.add(new BasicNameValuePair("sel", "1"));
nameValuePairs.add(new BasicNameValuePair("txt", "2466"));
nameValuePairs.add(new BasicNameValuePair("selr", "2011"));
httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
// Execute HTTP Post Request
HttpResponse response = httpclient.execute(httpPost);
content = response.getEntity().getContent();
return content;
// Update
Ok, now I am able to get the desired output from the web query.
I printed the result for my Http Post request and I saw some HTML tags in it. In short, it prints the source of the HTML page that has to be displayed.
Is there a way to display the HTML view in my Android Application? Or a way to fetch only the relavant data from the response and ignore the HTML tags etc..?
First line of the response looks like
06-17 16:35:21.756: DEBUG/(30307): <script language="javascript" type=text/css>
//
Regards,
Nirav
You need to speak with the owner/developer of the web site / service that you want to access. Only they can reliably tell you what their APIs are if you are unable to determine them yourself from WireShark captures.
I have configured the apache httpClient like so:
HttpProtocolParams.setContentCharset(httpParameters, "UTF-8");
HttpProtocolParams.setHttpElementCharset(httpParameters, "UTF-8");
I also include the http header "Content-Type: application/json; charset=UTF-8" for all http post and put requests.
I am trying to send http post/put requests with a json body that contains special characters (ie. chinese characters via the Google Pinyin keyboard, symbols, etc.) The characters appear as gibberish in the logs but I think this is because DDMS does not support UTF-8, as descibed in this issue.
The problem is when the server receives the request, it sometimes doesn't see the characters at all (especially the Chinese characters), or it becomes meaningless garbage when we retrieve it through a GET request.
I also tried putting 250 non-ascii characters in a single field because that particular field should be able to take up to 250 characters. However, it fails to validate at the server side which claims that the 250 character limit has been exceeded. 250 ASCII characters work just fine.
The server dudes claim that they support UTF-8. They even tried simulating a post request that contains Chinese characters, and the data was received by the server just fine. However, the guy (a Chinese guy) is using a Windows computer with the Chinese language pack installed (I think, because he can type Chinese characters on his keyboard).
I'm guessing that the charsets being used by the Android client and the server (made by Chinese guys btw) are not aligned. But I do not know which one is at fault since the server dudes claim that they support UTF-8, and our rest client is configured to support UTF-8.
This got me wondering on what charset Android uses by default on all text input, and if it can be changed to a different one programatically. I tried to find resources on how to do this on input widgets but I did not find anything useful.
Is there a way to set the charset for all input widgets in Android? Or maybe I missed something in the rest client configuration? Or maybe, just maybe, the server dudes are not using UTF-8 at their servers and used Windows charsets instead?
Apparently, I forgot to set the StringEntity's charset to UTF-8. These lines did the trick:
httpPut.setEntity(new StringEntity(body, HTTP.UTF_8));
httpPost.setEntity(new StringEntity(body, HTTP.UTF_8));
So, there are at least two levels to set the charset in the Android client when sending an http post with non-ascii characters.
The rest client itself itself
The StringEntity
UPDATE: As Samuel pointed out in the comments, the modern way to do it is to use a ContentType, like so:
final StringEntity se = new StringEntity(body, ContentType.APPLICATION_JSON);
httpPut.setEntity(se);
I know this post is a bit old but nevertheless here is a solution:
Here is my code for posting UTF-8 strings (it doesn't matter if they are xml soap or json) to a server. I tried it with cyrillic, hash values and some other special characters and it works like a charm. It is a compilation of many solutions I found through the forums.
HttpParams httpParameters = new BasicHttpParams();
HttpProtocolParams.setContentCharset(httpParameters, HTTP.UTF_8);
HttpProtocolParams.setHttpElementCharset(httpParameters, HTTP.UTF_8);
HttpClient client = new DefaultHttpClient(httpParameters);
client.getParams().setParameter("http.protocol.version", HttpVersion.HTTP_1_1);
client.getParams().setParameter("http.socket.timeout", new Integer(2000));
client.getParams().setParameter("http.protocol.content-charset", HTTP.UTF_8);
httpParameters.setBooleanParameter("http.protocol.expect-continue", false);
HttpPost request = new HttpPost("http://www.server.com/some_script.php?sid=" + String.valueOf(Math.random()));
request.getParams().setParameter("http.socket.timeout", new Integer(5000));
List<NameValuePair> postParameters = new ArrayList<NameValuePair>();
// you get this later in php with $_POST['value_name']
postParameters.add(new BasicNameValuePair("value_name", "value_val"));
UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(postParameters, HTTP.UTF_8);
request.setEntity(formEntity);
HttpResponse response = client.execute(request);
in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
StringBuffer sb = new StringBuffer("");
String line = "";
String lineSeparator = System.getProperty("line.separator");
while ((line = in.readLine()) != null) {
sb.append(line);
sb.append(lineSeparator);
}
in.close();
String result = sb.toString();
I hope that someone will find this code helpful. :)
You should set charset of your string entity to UTF-8:
StringEntity stringEntity = new StringEntity(urlParameters, HTTP.UTF_8);
You can eliminate the server as the problem by using curl to send the same data.
If it works with curl use --trace to check the output.
Ensure you are sending the content body as bytes. Compare the HTTP request from Android with the output from the successful curl request.