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.
Related
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!
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.
how to upload the datas to webserver from android mobile.Please provide coding
I think this compiles:
HttpPut request = new HttpPut(<uri>);
request.setEntity(new ByteArrayEntity(<your data>));
HttpResponse response = HttpClient.execute(httpPut);
You might want to use the HttpPost instead of HttpPut and also specify the content type on the request.