HttpURLConnection sending JSON POST request to Apache/PHP - java

I'm struggling with HttpURLConnection and OutputStreamWriter.
The code actually reaches the server, as I do get a valid error
response back. A POST request is made, but no data is received
server-side.
Any hints to proper usage of this thingy is highly appreciated.
The code is in an AsyncTask
protected JSONObject doInBackground(Void... params) {
try {
url = new URL(destination);
client = (HttpURLConnection) url.openConnection();
client.setDoOutput(true);
client.setDoInput(true);
client.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
client.setRequestMethod("POST");
//client.setFixedLengthStreamingMode(request.toString().getBytes("UTF-8").length);
client.connect();
Log.d("doInBackground(Request)", request.toString());
OutputStreamWriter writer = new OutputStreamWriter(client.getOutputStream());
String output = request.toString();
writer.write(output);
writer.flush();
writer.close();
InputStream input = client.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
StringBuilder result = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
result.append(line);
}
Log.d("doInBackground(Resp)", result.toString());
response = new JSONObject(result.toString());
} catch (JSONException e){
this.e = e;
} catch (IOException e) {
this.e = e;
} finally {
client.disconnect();
}
return response;
}
The JSON I'm trying to send:
JSONObject request = {
"action":"login",
"user":"mogens",
"auth":"b96f704fbe702f5b11a31524bfe5f136efea8bf7",
"location":{
"accuracy":25,
"provider":"network",
"longitude":120.254944,
"latitude":14.847808
}
};
And the response I get from the server:
JSONObject response = {
"success":false,
"response":"Unknown or Missing action.",
"request":null
};
And the response I should have had:
JSONObject response = {
"success":true,
"response":"Welcome Mogens Burapa",
"request":"login"
};
The server-side PHP script:
<?php
$json = file_get_contents('php://input');
$request = json_decode($json, true);
error_log("JSON: $json");
error_log('DEBUG request.php: ' . implode(', ',$request));
error_log("============ JSON Array ===============");
foreach ($request as $key => $val) {
error_log("$key => $val");
}
switch($request['action'])
{
case "register":
break;
case "login":
$response = array(
'success' => true,
'message' => 'Welcome ' . $request['user'],
'request' => $request['action']
);
break;
case "location":
break;
case "nearby":
break;
default:
$response = array(
'success' => false,
'response' => 'Unknown or Missing action.',
'request' => $request['action']
);
break;
}
echo json_encode($response);
exit;
?>
And the logcat output in Android Studio:
D/doInBackground(Request)﹕ {"action":"login","location":{"accuracy":25,"provider":"network","longitude":120.254944,"latitude":14.847808},"user":"mogens","auth":"b96f704fbe702f5b11a31524bfe5f136efea8bf7"}
D/doInBackground(Resp)﹕ {"success":false,"response":"Unknown or Missing action.","request":null}
If I append ?action=login to the URL I can get a success response from the server. But only the action parameter registers server-side.
{"success":true,"message":"Welcome ","request":"login"}
The conclusion must be that no data is transferred by URLConnection.write(output.getBytes("UTF-8"));
Well, data get transferred after all.
Solution offered by #greenaps does the trick:
$json = file_get_contents('php://input');
$request = json_decode($json, true);
PHP script above updated to show the solution.

echo (file_get_contents('php://input'));
Will show you the json text. Work with it like:
$jsonString = file_get_contents('php://input');
$jsonObj = json_decode($jsonString, true);

try to use DataOutputStream instead of OutputStreamWriter.
DataOutputStream out = new DataOutputStream(_conn.getOutputStream());
out.writeBytes(your json serialized string);
out.close();

I've made server tell me what it got from me.
Request Headers and POST Body
<?php
$requestHeaders = apache_request_headers();
print_r($requestHeaders);
print_r("\n -= POST Body =- \n");
echo file_get_contents( 'php://input' );
?>
Works like a charm)

The code actually reaches the server, as I do get a valid error
response back. A POST request is made, but no data is received
server-side.
got this same situation, and come to #greenapps answer.
you should know what server recieved from 'post request'
what i do first on the server side :
echo (file_get_contents('php://input'));
then print/Toast/show message response on the client side. make sure its correct form, like :
{"username": "yourusername", "password" : "yourpassword"}
if the response like this (because you post the request with yourHashMap.toString()) :
{username=yourusername,password=yourpassword}
instead using .toString(), use this method instead to turn HashMap into String :
private String getPostDataString(HashMap<String, String> postDataParams) {
StringBuilder result = new StringBuilder();
boolean first = true;
for (Map.Entry<String,String> entry : postDataParams.entrySet()){
if(first){
first = false;
}else{
result.append(",");
}
result.append("\"");
result.append(entry.getKey());
result.append("\":\"");
result.append(entry.getValue());
result.append("\"");
}
return "{" + result.toString() + "}";
}

Related

Converting HTTP POST from curl (PHP) to HttpURLConnection (Java)

I tried to convert the below PHP code (taken from https://www.cryptocoincharts.info/tools/api) to java
// define pairs
$post = array("pairs" => "ltc_usd,ppc_btc");
// fetch data
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, "http://api.cryptocoincharts.info/tradingPairs");
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $post);
$rawData = curl_exec($curl);
curl_close($curl);
// decode to array
$data = json_decode($rawData);
// show data
echo "<pre>";
foreach ($data as $row)
{
echo "Price of ".$row->id.": ".$row->price."\n";
echo "Trade this pair on ".$row->best_market."\n";
}
echo "</pre>";
Java Code
URL url = new URL("http://api.cryptocoincharts.info/tradingPairs");
HttpURLConnection con = (HttpURLConnection) url.openConnection();
// CURLOPT_POST
con.setRequestMethod("POST");
// CURLOPT_FOLLOWLOCATION
con.setInstanceFollowRedirects(true);
String postData = "ltc_usd,ppc_btc";
con.setRequestProperty("Content-length", String.valueOf(postData.length()));
con.setDoOutput(true);
con.setDoInput(true);
DataOutputStream output = new DataOutputStream(con.getOutputStream());
output.writeBytes(postData);
output.close();
// "Post data send ... waiting for reply");
int code = con.getResponseCode(); // 200 = HTTP_OK
System.out.println("Response (Code):" + code);
System.out.println("Response (Message):" + con.getResponseMessage());
// read the response
DataInputStream input = new DataInputStream(con.getInputStream());
int c;
StringBuilder resultBuf = new StringBuilder();
while ( (c = input.read()) != -1) {
resultBuf.append((char) c);
}
input.close();
System.out.println("resultBuf.toString() " + resultBuf.toString());
As per the API, after converting this to java I should get only the details of LTC and PPC details. Instead I am getting a strange Json with all trading pairs.
2 $post = array("pairs" => "ltc_usd,ppc_btc"); Posted the PHP code as I am not known the exact equivalent in Java
Could you please point out if my conversion from PHP to Java is correct ?
As far as I see, the main difference between the two implementation is related to the $post variable.
In the PHP implementation $post is a key/value array but in Java I only see the value part.
I suggest to change the postData variable content into pairs=ltc_usd,ppc_btc
You didn't mentioned key part, only value is mentioned. And when we fetch data from PHP API, we have an associative array. If u want to display the output, u need to know the key and value of the particular associative array.
And the InputStream and OutputStream should be inside try-resources
you can try curl-to-java lib to convert curl php code to java code
https://github.com/jeffreyning/curl-to-java
demo like this
public Object curl(String url, Object postData, String method) {
CurlLib curl = CurlFactory.getInstance("default");
ch = curl.curl_init();
curl.curl_setopt(ch, CurlOption.CURLOPT_CONNECTTIMEOUT, 1000);
curl.curl_setopt(ch, CurlOption.CURLOPT_TIMEOUT, 5000);
curl.curl_setopt(ch, CurlOption.CURLOPT_SSL_VERIFYPEER, false);
curl.curl_setopt(ch, CurlOption.CURLOPT_SSL_VERIFYHOST, false);
String postDataStr = "key1=v1";
curl.curl_setopt(ch, CurlOption.CURLOPT_CUSTOMREQUEST, "POST");
curl.curl_setopt(ch, CurlOption.CURLOPT_POSTFIELDS, postDataStr);
curl.curl_setopt(ch, CurlOption.CURLOPT_URL, "https://xxxx.com/yyy");
Object html = curl.curl_exec(ch);
Object httpCode = curl.curl_getinfo(ch, CurlInfo.CURLINFO_HTTP_CODE);
if (httpCode != null && 200 == Integer.valueOf(httpCode.toString())) {
return null;
}
return html;
}

Java - Illegal character(s) in message header value: Basic

I get the following error when trying to query an api in Java using HttpUrlConnection:
"Exception in thread "main" java.lang.IllegalArgumentException: Illegal character(s) in message header value: Basic MTk2YTVjODdhNWI2YjFmNWE3ZmQ5ODEtYjFjYTEzZmUtM2FkNC0xMWU1LWEyZjAtMDBkMGZlYTgy
NjI0OmY3NDQ2ZWQ0YjhjNzI2MzkyMzY1YzczLWIxY2ExNjQ4LTNhZDQtMTFlNS1hMmYwLTAwZDBm
ZWE4MjYyNA=="
Here is my code:
public class LocalyticsTest {
public static void main(String[] args) throws UnsupportedEncodingException {
String apiKey = "MyKey";
String apiSecret = "MySecretKey";
String apiUrl = "https://api.localytics.com/v1/query";
String credentials = apiKey + ":" + apiSecret;
//String encoding = Base64.encode(apiKey.getBytes("UTF-8"));
//String encoding2 = Base64.encode(apiSecret.getBytes("UTF-8"));
String encoding3 = new sun.misc.BASE64Encoder().encode (credentials.getBytes("UTF-8"));
String appId = "myAppId";
String metric = "sessions";
String dimensions = "day";
String condition = "'{\"day\":[\"between\",\"'.$newDate.'\",\"'.$newDate.'\"]}'";
Map data = new HashMap();
data.put("app_id", appId);
data.put("metric", metric);
data.put("dimensions", dimensions);
data.put("condition", condition);
QueryEncoder q = new QueryEncoder();
String newData = q.toQueryString(data);
String newUrl = String.format("%s?%s", apiUrl, newData);
try{
URL url = new URL(newUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//conn.setRequestMethod("GET");
//conn.setRequestProperty("Authorization", "Basic");
//conn.setRequestProperty(apiKey,apiSecret);
conn.setRequestProperty("Authorization", "Basic " + encoding3);
conn.setRequestProperty("Accept", "application/vnd.localytics.v1+hal+json");
if (conn.getResponseCode() != 200) {
throw new RuntimeException("Failed : HTTP error code : "
+ conn.getResponseCode());
}
BufferedReader br = new BufferedReader(new InputStreamReader(
(conn.getInputStream())));
String output;
System.out.println("Output from Server .... \n");
while ((output = br.readLine()) != null) {
System.out.println(output);
}
conn.disconnect();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (ProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
I am able to get it to work fine in php with Curl with the following:
function call_localytics_api($method, $url, $data)
{
$curl = curl_init();
$url = sprintf("%s?%s", $url, http_build_query($data));
$api_key = "myKey";
$api_secret = "mySecret";
// Optional Authentication:
curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($curl, CURLOPT_USERPWD, $api_key . ":" . $api_secret);
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
// Disable the SSL verificaiton process
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_HTTPHEADER, array("Accept: application/vnd.localytics.v1+hal+json"));
// Confirm cURL gave a result, if not, write the error
$response = curl_exec($curl);
if ($response === FALSE) {
die("Curl Failed: " . curl_error($curl));
} else {
return $response;
}
}
$api_querystring = "https://api.localytics.com/v1/query";
$app_id = "myAppId";
$metric = "sessions";
$dimensions = "day";
//$data = array(app_id => $app_id, metrics => $metric, dimensions => $dimensions, conditions => '{"day":["in","'.$requestDate.'"]}');
$data = array(app_id => $app_id, metrics => $metric, dimensions => $dimensions, conditions => '{"day":["between","'.$newDate.'","'.$newDate.'"]}');
$response = call_localytics_api('GET', $api_querystring, $data);
$json = json_decode($response);
print_r($json);
Just need help getting it to work in Java.
It appears the illegal character is a newline. Use a base 64 encoder that doesn't put newlines in the result, or remove the newline yourself.
As of Java 8, you should use:
String encoding3 = Base64.getEncoder().encodeToString(
credentials.getBytes(StandardCharsets.UTF_8));
In older versions of Java, you can use DatatypeConverter:
String encoding3 = DatatypeConverter.printBase64Binary(
credentials.getBytes(StandardCharsets.UTF_8));
You could also remove the newline character directly, but you should use one of the above approaches instead. The sun.* classes are not for development use, and they can change or disappear from one Java release to the next. Furthermore, as I understand it, they may not even be usable at all as of Java 9, regardless of whether they exist, due to module restrictions.

Request to server API using Java and JSON

I have documentation of server API with several methods. The problem is that I have never used API to work with server. What I can do to do it more easy?
Part of API documentation:
Method "Login":
POST http://api.example.com/login-ajax
Parameters:
email
password
Response:
{
"success":true,
"currentUser":222,
"userData":{
"displayName":"User",
"displayAvatarId":"asjhdsasduh",
"email":"qwerty#gmail.com",
"isEmailConfirmed":"0",
"sex":"m"
}
}
The response is JSON object, but I don't know how to send request to get this response.
Help me please.
UPGRADE
I tried to use Jsoup:
Connection.Response res = Jsoup.connect("http://api.example.com/login-ajax")
.data("email", "mail#gmail.com", "password", "pass")
.method(Connection.Method.POST)
.header("Accept", "application/json")
.header("X-Requested-With", "XMLHttpRequest")
.header("X-App-Api", "1.0")
.header("X-App", "iOS")
.ignoreContentType(true)
.execute();
Document document = Jsoup.parse(res.parse().outerHtml());
System.out.println(document.text());
The response is:
{"success":false,"exception":"Exception_User","message":"\u041c\u044b \u043d\u0435 \u043d\u0430\u0448\u043b\u0438 \u0432 \u0431\u0430\u0437\u0435 \u0442\u0430\u043a\u043e\u0435 \u0441\u043e\u0447\u0435\u0442\u0430\u043d\u0438\u0435 \u044d\u043b. \u043f\u043e\u0447\u0442\u044b \u0438 \u043f\u0430\u0440\u043e\u043b\u044f. \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0435\u0449\u0435 \u0440\u0430\u0437."}
UPGRADE 2
I also tried to use this one:
System.out.println(getJSON("http://api.example.com/login-ajax"));
public static String getJSON(String url) {
try {
URL u = new URL(url);
HttpURLConnection c = (HttpURLConnection) u.openConnection();
c.setRequestMethod("POST");
c.setRequestProperty("email", "mail#gmail.com");
c.setRequestProperty("password", "pass");
c.setRequestProperty("Accept", "application/json");
c.setRequestProperty("X-Requested-With", "XMLHttpRequest");
c.setRequestProperty("X-App-Api", "1.0");
c.setRequestProperty("X-App", "iOS");
c.setUseCaches(false);
c.setAllowUserInteraction(false);
c.setConnectTimeout(1000);
c.setReadTimeout(1000);
c.connect();
int status = c.getResponseCode();
switch (status) {
case 200:
System.out.println("200");
BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream()));
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line + "\n");
}
br.close();
return sb.toString();
case 201:
System.out.println("201");
br = new BufferedReader(new InputStreamReader(c.getInputStream()));
sb = new StringBuilder();
while ((line = br.readLine()) != null) {
sb.append(line + "\n");
}
br.close();
return sb.toString();
}
} catch (MalformedURLException ex) {
System.out.println("MalformedURLException");
} catch (IOException ex) {
System.out.println("IOException");
}
return null;
}
And the response is:
{"success":false,"exception":"Exception_Validation","message":"\u041d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439 e-mail","errors":{"email":["\u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u0432\u0432\u0435\u0434\u0438\u0442\u0435 e-mail."],"password":["\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u043f\u0430\u0440\u043e\u043b\u044c"]}}
As I haven't used Jsoup so far I can't give detailed information on how to use it, but I had to work with Restlet and therefore created my own JSON messages (either via org.json.JSONObject or via plain String). A post-example using Restlet would look something like this:
try
{
// create a Restlet client
ClientResource cr = new ClienResource("http://api.example.com/login-ajax");
// create the JSON message
JSONObject message = new JSONObject();
message.put("email", "mail#gmail.com");
message.put("password", "pass");
// use HTTP POST method to send the JSON message
cr.post(message, MediaType.APPLICATION_JSON);
// receive the answer - error checks omitted!
Response response = cr.getResponse();
JsonRepresentation jsonRep = new JsonRepresentation(response.getEntity());
// process the JSON response
JSONObject json = jsonRep.getJsonObject();
System.out.println("success: "+json.get("success"));
System.out.println("current user: "+json.get("currentUser"));
// extract the user data
JSONObject userData = (JSONObject)json.get("userData");
System.out.println("display name: "+userData.get("displayName"));
System.out.println("display avatar Id: "+userData.get("displayAvatarId"));
System.out.println("email: "+userData.get("email"));
System.out.println("is email confirmed: "+userData.get("isEmailConfirmed"));
System.out.println("sex: "+userData.get("sex"));
}
catch (ResourceException | JSONException ex)
{
ex.printStackTrace();
}
HTH
Consider to use an Apache HTTP Client to create a connection to your HTTP server.
Its a general-purpose library for working with HTTP requests. There are plenty resources that illustrate the usage of HTTP client, Here is an example
I admit, I've never used JSoup so I can't really comment on your example.
Hope this helps,
Mark

Chunked Steam error in android HTTP post

I'm working on creating an android app that will pull down user data from a MySQL database stored on a web server. I've read a few tutorials on HTTP Post that allows me to connect to the database, which I got working. However, I am unable to process the data that gets sent from the php.
The error I receive is: org.apache.http.MalformedChunkCodingException: Chunked stream ended unexpectedly.
This is the code I have written:
String name = username.getText().toString(); //username is a TextView field
ArrayList<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(1);
nameValuePairs.add(new BasicNameValuePair("user",name));
try
{
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(location);
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
is = entity.getContent();
}
catch(Exception e)
{
Toast.makeText(getBaseContext(), e.toString(), Toast.LENGTH_LONG).show();
Log.e("log_tag", "Error in http connection"+e.toString());
}
//Convert response to string
try
{
BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null)
{
sb.append(line + "\n");
}
is.close();
result = sb.toString();
Log.i("log_tag", result);
}
catch(Exception e)
{
Toast.makeText(getBaseContext(),e.toString() ,Toast.LENGTH_LONG).show();
Log.e("log_tag", e.toString());
}
The error seems to appear in the convert response to string section. I've looked up several issues regarding similar errors to the one I received but what I read didn't seem to help much or I just don't know enough about http client coding...probably the latter. Any help would be greatly appreciated, thanks!
Here is the PHP as well:
<?php
$con = mysqli_connect("/**connection*/");
if (mysqli_connect_errno())
{
echo "Failed to connect to MySQL: ".mysqli_connect_error();
}
$result = mysqli_query($con, "SELECT * FROM userNames WHERE user='".$_POST['name']."')";
if ($result == NULL)
{
die();
}
else
{
//TODO:get row to java
$rows = array();
while($r = mysql_fetch_assoc($result))
{
$rows[] = $r;
}
print json_encode($rows);
mysql_close();
}
mysqli_close($con);
}
?>
The end goal of this is to convert the JSON response from the database into separate variables, the buffered reader stuff is just a middle step before the JSON conversion. Again , I just followed a tutorial so if anyone knows a different way of going about this I'm open to suggestions.

How to call PHP function from Android?

I want to call specific php function on server and also to send some parameters.
Till now I achieved that I can open php file using HttpClient and executed data transfer to Json and show that in my app.
So, now I want to be able to call specific function and send parameter to it, how can I do that??
Sorry I didn't mansion that I need to call that function from Android.
here some code:
try {
HttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost("http://10.0.2.2/posloviPodaci/index.php");
HttpResponse response = httpClient.execute(httpPost);
HttpEntity entity = response.getEntity();
is = entity.getContent();
} catch (Exception e) {
Log.e("log_tag", "Error in http connection" + e.toString());
}
// Convert response to string
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(is, "iso-8859-1"), 8);
sb = new StringBuilder();
sb.append(reader.readLine() + "\n");
String line = "0";
while((line = reader.readLine()) != null){
sb.append(line + "\n");
}
is.close();
result = sb.toString();
} catch (Exception e) {
Log.e("log_tag", "Error converting result " + e.toString());
}
// Parsing data
JSONArray jArray;
try {
jArray = new JSONArray(result);
JSONObject json_data = null;
items = new String[jArray.length()];
for(int i = 0; i < jArray.length(); i++) {
json_data = jArray.getJSONObject(i);
items[i] = json_data.getString("naziv");
}
} catch (Exception e) {
// TODO: handle exception
}
Thanks in advance,
Wolf.
If you are working with an MVC framework, such as CakePHP, you can simply create a route to a function that will output whatever JSON you'd like.
Otherwise,
You can utilize something simple at the top of your index.php such as this:
<?php
function foo($bar) { echo $bar; }
if(isset($_GET['action']) && (strlen($_GET['action']) > 0)) {
switch($_GET['action']) :
case 'whatever':
echo json_encode(array('some data'));
break;
case 'rah':
foo(htmlentities($_GET['bar']));
break;
endswitch;
exit; # stop execution.
}
?>
This will let you call the url with a parameter of action.
http://10.0.2.2/posloviPodaci/index.php?action=whatever
http://10.0.2.2/posloviPodaci/index.php?action=rah&bar=test
If you need to pass more sensitive data, I recommend you stick with $_POST and utilize some form of encryption.
You can handle that on php side. Create a Json object with a field called command and maybe a list of arguments.
On the php end after you decode the json just do:
if($obj.command == "foo"){
foo($obj.arg[0],$obj.arg[1]);
}

Categories

Resources