Just as a demonstration the code will work, I am attempting to fetch some JSON data within my oncreate function. I know it should run on a different thread but I want to be sure the code successfully fetches my JSON before moving it into it's own thread.
The code is below:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
/***************************************************/
final String TAG = "PostFetcher";
final String SERVER_URL = "http://kylewbanks.com/rest/posts";
// final String TAG = "PostsActivity";
// List<Post> posts;
try {
//Create an HTTP client
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(SERVER_URL);
//Perform the request and check the status code
HttpResponse response = client.execute(post);
StatusLine statusLine = response.getStatusLine();
if(statusLine.getStatusCode() == 200) {
HttpEntity entity = response.getEntity();
InputStream content = entity.getContent();
try {
//Read the server response and attempt to parse it as JSON
Reader reader = new InputStreamReader(content);
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setDateFormat("M/d/yy hh:mm a");
Gson gson = gsonBuilder.create();
List<JsonObject> posts = new ArrayList<JsonObject>();
Log.e(TAG, "Checking: " + posts);
// posts = Arrays.asList(gson.fromJson(reader, JsonObject[].class));
content.close();
} catch (Exception ex) {
Log.e(TAG, "Failed to parse JSON due to: " + ex);
}
} else {
Log.e(TAG, "Server responded with status code: " + statusLine.getStatusCode());
}
} catch(Exception ex) {
Log.e(TAG, "Failed to send HTTP POST request due to: " + ex);
}
}
When I run the code, I get the second to last exception message:
Server responded with status code: 500
Can anyone please tell me what I'm doing wrong?
You are sending a HttpPost request to (obviously) an website that uses RESTful styled API.
This means, it works with HTTP Verbs (GET, POST, PUT, DELETE).
If you want to read data and the read access never changes data, use GET.
If you want to update or replace data, user PUT or POST (put usually to replace, POST to change/add). However, JavaScript does (or did) only support GET and POST requests, so keep that in mind.
If you want to delete a resource or collection, use DELETE.
That being said: If you want to load data, use Get in your case HttpGet instead of HttpPost.
Also read more about RESTful web APIs.
Edit:
In fact, calling the given URL in Fiddler2 (as stated in the comment on the other answer) results a HTML website reporting the error:
You called this URL via POST, but the URL doesn't end in a slash and
you have APPEND_SLASH set. Django can't redirect to the slash URL
while maintaining POST data. Change your form to point to
kylewbanks.com/rest/posts/ (note the trailing slash), or set
APPEND_SLASH=False in your Django settings.
Its internal server error..check if there are any exceptions are getting thrown at server side.
It has nothing to do with your android code, the problem is at server.
You can use AsyncTask to run network/filesystem related operations.
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
The php files on my server are password protect with htaccess. How can I make request to these files through my android app?
I couldnt find any relevant answers with google search.
Here you can find your answer:
Basic HTTP Authentication on Android
Basically:
HttpUriRequest request = new HttpGet(YOUR_URL); // Or HttpPost(), depends on your needs
String credentials = YOUR_USERNAME + ":" + YOUR_PASSWORD;
String base64EncodedCredentials = Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);
request.addHeader("Authorization", "Basic " + base64EncodedCredentials);
HttpClient httpclient = new DefaultHttpClient();
httpclient.execute(request);
// You'll need to handle the exceptions thrown by execute()
You can replace the last line with:
EDITED:
You can try someting like this:
try {
HttpResponse response = httpclient.execute(request);
//this is the login response, logged so you can see it - just use the second part of the log for anything you want to do with the data
Log.d("Login: Response", EntityUtils.toString(response.getEntity()));
} catch (IOException e) {
//if something went badly wrong
}
So you can view your response, maybe the problem is parsing the JSON.
Assuming your PHP files are protected by HTTP Basic Authentication, you can request your php files using this special URL syntax:
http://validuser:validpassword#www.domain.com/validfile.php
I am trying to invoke a private web-service in which there's one link I've to access using GET method. While using the direct URL on browser (needs to login first), I get the data in JSON format. The URL I am invoking is like this
http://www.example.com/trip/details/860720?format=json
The url is working fine, but when I invoke this using HttpGet, I am getting the HTML coding of the webpage, instead of the JSON String. The code I am using is as follows:
private String runURL(String src,int id) { //src="http://www.example.com/trip/details/"
HttpClient httpclient = new DefaultHttpClient();
HttpGet httpget = new HttpGet(src);
String responseBody="";
BasicHttpParams params=new BasicHttpParams();
params.setParameter("domain", token); //The access token I am getting after the Login
params.setParameter("format", "json");
params.setParameter("id", id);
try {
httpget.setParams(params);
HttpResponse response = httpclient.execute(httpget);
responseBody = EntityUtils.toString(response.getEntity());
Log.d("runURL", "response " + responseBody); //prints the complete HTML code of the web-page
} catch (Exception e) {
e.printStackTrace();
}
return responseBody;
}
Can you tell me what am I doing wrong here??
Try specify Accept & Content-Type in you http header:
httpget.setHeader("Accept", "application/json"); // or application/jsonrequest
httpget.setHeader("Content-Type", "application/json");
Note that you can use tools like wireshark capture and analyse the income and outcome http package, and figure out the exact style of the http header that returns your json response from a standard browser.
Update:
You mentioned need login first when using browser, the html content returned is probably the login page (if use basic authentication type, it returns a short html response with status code 401, so a modern browser knows how to handle, more specifically, pop up login prompt to user), so the first try would be checking the status code of your http response:
int responseStatusCode = response.getStatusLine().getStatusCode();
Depend on what kind of authentication type you use, you probably need specify login credentials in your http request as well, something like this (if it is a basic authentication):
httpClient.getCredentialsProvider().setCredentials(
new AuthScope("http://www.example.com/trip/details/860720?format=json", 80),
new UsernamePasswordCredentials("username", "password");
I am using the Jackson JSON parser as I heard it was a lot more efficient than the default Android parser. I learned how to use it off this tutorial here
http://www.mkyong.com/java/jackson-streaming-api-to-read-and-write-json/
which is great tutorial if anyone wants to learn how to use Jackson json parser.
However, I am having an issue in that I can parse data fine in Java from a URL, however when I use Jackson with Android, I get null values or the screen just shows up black for some reason.
In order to retrieve the data from the website I am using this code from here
http://www.javacodegeeks.com/2011/01/android-json-parsing-gson-tutorial.html
private InputStream retrieveStream(String url) {
DefaultHttpClient client = new DefaultHttpClient();
HttpGet getRequest = new HttpGet(url);
try {
HttpResponse getResponse = client.execute(getRequest);
final int statusCode = getResponse.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
Log.w(getClass().getSimpleName(),
"Error " + statusCode + " for URL " + url);
return null;
}
HttpEntity getResponseEntity = getResponse.getEntity();
return getResponseEntity.getContent();
}
catch (IOException e) {
getRequest.abort();
Log.w(getClass().getSimpleName(), "Error for URL " + url, e);
}
return null;
}
Then in my parse data method
InputStream source = retrieveStream(url);
try {
JsonFactory jfactory = new JsonFactory();
JsonParser jParser = jfactory.createJsonParser(source);
Then I parse data as was shown in the tutorial I linked above
while (jParser.nextToken() != JsonToken.END_OBJECT) {
String fieldname = jParser.getCurrentName();
if ("Name".equals(fieldname)) {
jParser.nextToken();
this.setName(jParser.getText());
}
if ("Number".equals(fieldname)) {
jParser.nextToken();
this.setNumber(jParser.getText());
}
}
The url I am using is a dummy site set up which just has a JSON file on it which I am using to practice Jackson JSON parsing.
Now I know my parse data code is fine, as I in normal Java class, I can parse the data from the website using the code I created, and it works fine.
However if I try to use the code in Android with the code I have just shown, I just get a black screen for some odd reason. I have internet permissions enabled in manifest
Is there something wrong with the http code I have used? If so could someone show me how it should be done? And also why I am getting a black screen, I don't understand why it would show that.
Thanks in advance
Not sure if this is the problem, but your looping construct is unsafe: depending on kind of data you get, it is quite possible that you do not get END_OBJECT as the next token. And at the end of content, nextToken() will return null to indicate end-of-input. So perhaps you get into infinite loop with certain input?
I found the issue, the link was local host which could not be accessed from Emulator. Settings were changed, and can now access link, works perfectly now :D
How would one go about sending data back to server, from an android application?
I've already tried using HttpPost and posted back to a RESTful WCF service, but I couldnt get that to work (I've already created a SO question about this, without finding the solution..) - No matter what I do I keep getting 405 Method not allowed or the 400 Bad Request.. :(
I'm not asking for full code example necessarily.. just a pointer in a direction, which can enable me to send data back to a server.
It is important that the user should not have to allow or dismiss the transfer.. it should happen under the covers, so to speak
Thanks in advance
Services is the way to go. REST (I recommend this one on Android), or SOAP based. There're loads of tutorials on getting an android app communicate a service, even with .net / wcf ones.
Tho you can always just open raw sockets and send data with some custom protocol.
Edit:
Here's the doInBackground part of my asynctask handling http post communication, maybe that'll help:
protected String doInBackground(String... req) {
Log.d(TAG, "Message to send: "+req[0]);
HttpPost p = new HttpPost(url);
try{
p.setEntity(new StringEntity(req[0], "UTF8"));
}catch(Exception e){
e.printStackTrace();
}
p.setHeader("Content-type", "application/json");
String response = "";
try{
HttpResponse resp = hc.execute(p, localContext);
InputStream is = resp.getEntity().getContent();
response = convertStreamToString(is);
Log.d("Response", "Response is " + response);
} catch (Exception e){
e.printStackTrace();
}
return response;
}