I have created a Django Rest server. And I am trying to POST a JSON content in java using HttpURLConnection. However, when I am registering OutputStream in java, the server get a POST request with no JSON content. Hence the server rejecting the request with HTTP response code 400. I did write JSON data just after registering OutputSream. May be POST has been made before writing to OutputStream. The following is the code in JAVA.
public static void post(HttpURLConnection urlConnection1)
throws IOException, InterruptedException {
// urlConnection.setRequestMethod("POST");
URL url = new URL("http://127.0.0.1:8000/message/");
byte[] authStr=Base64.encodeBase64("sp:password".getBytes());
String enc=new String(authStr);
HttpURLConnection urlConnection = (HttpURLConnection) url
.openConnection();
urlConnection.setRequestProperty("Authorization", "Basic "+ enc);
try {
urlConnection.setDoOutput(true);
urlConnection.setChunkedStreamingMode(0);
urlConnection
.setRequestProperty("Content-Type", "application/json");
urlConnection.setRequestMethod("POST");
urlConnection.setInstanceFollowRedirects(false);
OutputStream out = urlConnection.getOutputStream();
//Thread.sleep(5000);
writeStream(out);
out.flush();
InputStream in = urlConnection.getInputStream();
readStream(in);
} finally {
urlConnection.disconnect();
}
}
private static void writeStream(OutputStream out) {
// TODO Auto-generated method stub
try {
JSONObject grp = new JSONObject();
JSONObject gp = new JSONObject();
gp.put("id", "g3bj25");
gp.put("from", "someone");
out.write(gp.toString().getBytes());
System.out.println(gp.toString());
} catch (IOException | JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Do I have to make any changes in server side so that it waits for content?
The problem is, that your URL is not complete, the name of the script is missing.
URL url = new URL("http://127.0.0.1:8000/message/");
supposes that you are calling http://127.0.0.1/message/index.php but here you're not allowed to let the index.php (or whatever) implicit.
The script gets called, but the POST data is not sent, or it is truncated by the Webserver when handling the request. I had the same problem and spent hours until I found the reason. Then I did not dig further to find out exactly where the POST data gets dropped.
Related
I'm trying to download a zip file through a java program using GitHub API.
The program I'm using is the following:
public static void main(String[] args) {
// create client
HttpClient client = HttpClient.newHttpClient();
// create request
HttpRequest request = HttpRequest.newBuilder().uri(URI.create("https://api.github.com/repos/:owner/:repo/zipball/:ref")).build();
// use the client to send the asynchronous request
InputStream is = client.sendAsync(request, BodyHandlers.ofInputStream())
.thenApply(HttpResponse::body).join();
try {
FileOutputStream out = new FileOutputStream("outputZipFile.zip");
copy(is,out,1024);
out.close();
}catch(Exception e) {}
}
private static void copy(InputStream is, FileOutputStream out, int i) {
// TODO Auto-generated method stub
byte[] buf = new byte[i];
try {
int n = is.read(buf);
while(n>=0) {
out.write(buf,0,n);
n=is.read(buf);
}
out.flush();
}catch(IOException ioe) {
System.out.println(ioe.getStackTrace());
}
}
When I try to run this I get empty body so the output file will be empty as well.
I noticed that using HttpURLConnection insted of Java11 HttpClient makes it work but I'd prefer to use this Java11 feature in order to send asynchronous requests.
I can't understand what I'm doing wrong.
EDIT: The HttpURLConnection code I'm using at the moment is the following:
private void downloadVersion(String sha, String outputDestination) {
try {
URL url = new URL( getDownloadQuery(sha) );
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
if(authToken!=null)
connection.setRequestProperty("Authorization", "Bearer " + authToken) ;
connection.setRequestMethod("GET");
InputStream in = connection.getInputStream();
FileOutputStream out = new FileOutputStream(outputDestination);
copy(in, out, 1024);
out.close();
} catch (Exception e) {}
}
Your url (when set to correct github repos) may be returning redirect status 302. To make HTTP client follow redirects replace HttpClient client = HttpClient.newHttpClient() with use of HttpClient.newBuilder(). You can also simplify your code with try with resources and making use of InputStream.transferTo:
HttpClient client = HttpClient.newBuilder().followRedirects(Redirect.ALWAYS).build();
URI uri = URI.create("https://api.github.com/repos/:owner/:repo/zipball/:ref");
HttpRequest request = HttpRequest.newBuilder().uri(uri).build();
// use the client to send the asynchronous request
InputStream is = client.sendAsync(request, BodyHandlers.ofInputStream())
.thenApply(HttpResponse::body).join();
try (FileOutputStream out = new FileOutputStream("outputZipFile.zip")) {
is.transferTo(out);
}
I'm trying to send JSON using the code below in Android. I don't have access to server side code just database where data supposed to be stored. The guy who handles the server side says he sees my request as GET. I really don't understand why. I tried several examples I found on the internet and none of them worked.
public void uploadNewTask(View view) {
AsyncT asynct = new AsyncT();
asynct.execute();
}
class AsyncT extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
try {
URL url = new URL("http://[...]/events/");
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setDoOutput(true);
httpURLConnection.setRequestMethod("POST");
httpURLConnection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
httpURLConnection.setRequestProperty("Accept", "application/json; charset=UTF-8");
httpURLConnection.connect();
JSONObject jsonObject = new JSONObject();
jsonObject.put("title", "tytul1");
jsonObject.put("description", "opis1");
jsonObject.put("execution_time", "2017-05-01 12:30:00");
/*
OutputStreamWriter writer = new OutputStreamWriter(httpURLConnection.getOutputStream());
String output = jsonObject.toString();
writer.write(output);
writer.flush();
writer.close();*/
DataOutputStream wr = new DataOutputStream(httpURLConnection.getOutputStream());
wr.writeBytes(jsonObject.toString());
wr.flush();
wr.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
}
Here's my suggestion to you: Use libraries to make your work easy. Libraries that do most of the work for you and makes request faster and better error handling.
So how do you make a POST call?
Step 1: Add these two libraries to your gradle dependencies:
compile 'com.google.code.gson:gson:2.8.0' // to work with Json
compile 'com.squareup.okhttp:okhttp:2.7.5' // to make http requests
Step 2: Create POST body JSON object and make a POST call.
Declare this in your Activity/Fragment:
final MediaType jsonMediaType = MediaType.parse("application/json");
Then, in your AsyncTask, do this:
try {
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("title", "tytul1");
jsonObject.addProperty("description", "opis1");
jsonObject.addProperty("execution_time", "2017-05-01 12:30:00");
RequestBody requestBody = RequestBody.create(jsonMediaType, new Gson().toJson(jsonObject));
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://[...]/events/")
.post(requestBody)
.addHeader("content-type", "application/json")
.build();
Response response = client.newCall(request).execute();
// this is the response of the post request
String res = response.body().string();
// you can get the response as json like this
JsonObject responseJson = new Gson().fromJson(res, JsonObject.class);
} catch (Exception e) {
Log.e(TAG, e.toString());
}
Note: If you want more example about this network library, see their official examples here
if you want to send get request, why there are not string like this format.http://xxx?requestParam=value&requestparam2=value2 format. I remember i used such way send get request to server side in my project do have string concatenation.
I use a simple WebServer from http://www.java2s.com/Code/Java/Network-Protocol/AverysimpleWebserverWhenitreceivesaHTTPrequestitsendstherequestbackasthereply.htm
and Android code from Sending json object via http post method in android
In my main Activity:
AsyncT asyncT = new AsyncT();
asyncT.execute();
Class:
class AsyncT extends AsyncTask<Void,Void,Void>{
#Override
protected Void doInBackground(Void... params) {
try {
URL url = new URL(""); //Enter URL here
HttpURLConnection httpURLConnection = (HttpURLConnection)url.openConnection();
httpURLConnection.setDoOutput(true);
httpURLConnection.setRequestMethod("POST"); // here you are telling that it is a POST request, which can be changed into "PUT", "GET", "DELETE" etc.
httpURLConnection.setRequestProperty("Content-Type", "application/json"); // here you are setting the `Content-Type` for the data you are sending which is `application/json`
httpURLConnection.connect();
JSONObject jsonObject = new JSONObject();
jsonObject.put("para_1", "arg_1");
DataOutputStream wr = new DataOutputStream(httpURLConnection.getOutputStream());
wr.writeBytes(jsonObject.toString());
wr.flush();
wr.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
}
The connection is established without any errors ("HostConnection::get() New Host Connection established"). However, I am not able to get in my Java server any information from the request. When I read from input stream
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
System.out.println(in);
I get java.io.BufferedReader#4d7hge12
And this outputs nothing:
String line;
while ((line = in.readLine()) != null) {
if (line.length() == 0)
break;
System.out.println(line);
}
Don't re-invent the wheel and use a library for this.
For example okhttp:
public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
OkHttpClient client = new OkHttpClient();
String post(String url, String json) throws IOException {
RequestBody body = RequestBody.create(JSON, json);
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
Response response = client.newCall(request).execute();
return response.body().string();
}
If you want to call a REST-API you can use retrofit (which is build ontop of okhttp)
Assuming you're doing this as a learning exercise, so using another library isn't what you're looking for, I would suggest a couple of things:
(1) install Wireshark and see what the actual response coming back the server is, does it look sensible?
(2) break that line of code out into separate lines, is the InputStream / InputStreamReader null?
I'm trying to make PUT request with JSON data using HttpURLConnection in Java. The way I do it doesn't work. I get no errors so I don't know what the problem is.
public static void main(String[] args) {
URL url;
try {
url = new URL("http://fltspc.itu.dk/widget/515318fe17450f312b00153d/");
HttpURLConnection hurl = (HttpURLConnection) url.openConnection();
hurl.setRequestMethod("PUT");
hurl.setDoOutput(true);
hurl.setRequestProperty("Content-Type", "application/json");
hurl.setRequestProperty("Accept", "application/json");
String payload = "{'pos':{'left':45,'top':45}}";
OutputStreamWriter osw = new OutputStreamWriter(hurl.getOutputStream());
osw.write(payload);
osw.flush();
osw.close();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
And here is the request I'm actually trying to make:
I was already making GET requests to the resource within the same app and it worked fine. I would be very grateful for all tips on how can I debug that or how can I try to do it some other way. So far I tried only using OutputStream instead of OutputStreamWriter but it doesn't work neither.
The Sun (Oracle) implementation of HttpURLConnection caches the content of your post unless you tell it to be in streaming mode. The content will be sent if you start interaction with the response such as:
hurl.getResponseCode();
Also, according to RFC 4627 you can not use single quotes in your json (although some implementations seem to not care).
So, change your payload to:
String payload = "{\"pos\":{\"left\":45,\"top\":45}}";
This example works for me
public class HttpPut {
public static void main(String[] args) throws Exception {
Random random = new Random();
URL url = new URL("http://fltspc.itu.dk/widget/515318fe17450f312b00153d/");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("PUT");
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("Accept", "application/json");
OutputStreamWriter osw = new OutputStreamWriter(connection.getOutputStream());
osw.write(String.format("{\"pos\":{\"left\":%1$d,\"top\":%2$d}}", random.nextInt(30), random.nextInt(20)));
osw.flush();
osw.close();
System.err.println(connection.getResponseCode());
}
}
I suspect I'm running into some issues borne out of threading in my simple Android app.
I have a Activity which does the following:
runs a dialog on main thread
spins a background thread and hits a PHP script for retreiving data using DefaultHttpClient and close this connection. This successfully returns a URL to a picture on the internet
open HttpUrlConnection called conn and try conn.connect
app freezes at this point with no error
Not sure what code to put here, I could paste it all but that would be too much so let me know if any more info is needed:
/**
* Background Async Task to Load all Question by making HTTP Request
*/
class LoadAllImages extends AsyncTask<String, String, String> {
/**
* Before starting background thread Show Progress Dialog
* */
#Override
protected void onPreExecute() {
super.onPreExecute();
// dialog init'd here
}
#Override
protected String doInBackground(String... args) {
// Building Parameters
List<NameValuePair> params = new ArrayList<NameValuePair>();
// getting JSON string from URL
JSONObject json = jParser.makeHttpRequest(url_question_details, "GET", params);
// Check your log cat for JSON response
Log.d("All Questions: ", json.toString());
try {
// images found
// Getting Array of questions
images = json.getJSONArray(TAG_IMAGES);
// looping through All questions
for (int i = 0; i < images.length(); i++) {
JSONObject c = images.getJSONObject(i);
// Storing each json item in variable
String id = c.getString(TAG_IMAGEID);
String location = c.getString(TAG_IMAGELOCATION);
URL myFileUrl = null;
try {
myFileUrl = new URL(location);
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
HttpURLConnection conn = (HttpURLConnection) myFileUrl.openConnection();
conn.setDoInput(true);
conn.connect(); // freezes here
int length = conn.getContentLength();
int[] bitmapData = new int[length];
byte[] bitmapData2 = new byte[length];
InputStream is = conn.getInputStream();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
First of all make sure you added Internet Permission to manifest:
<uses-permission android:name="android.permission.INTERNET" />
outside the application tag in your AndroidManifest.xml
Troubleshooting:
Try access the same URL using your browser
Check if you are not behind proxy or server is not behind proxy
Try pinging the server see and check the latency.
Try catching all exceptions:
Change } catch (IOException e) { to } catch (Exception e) {
If all looks good try this code:
System.setProperty("http.keepAlive", "false");
HttpURLConnection conn = (HttpURLConnection) myFileUrl.openConnection();
conn.setUseCaches(false);
conn.setConnectTimeout(30000);
conn.setDoOutput(true);
conn.setDoInput(true);
//conn.connect(); // You are allready connected after openConnection().
If still no luck, try using HttpClient & HttpGet this way:
final HttpClient client = new DefaultHttpClient();
final HttpGet conn = new HttpGet(myFileUrl.toString());
HttpResponse response = client.execute(conn);
InputStream is = response.getEntity().getContent();
I'd at least put both connect and read timeout in, e.g.
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
I had the exact same issue that drove me crazy to solve. I was already setting the timout params, but the httpurlconnection was hanging on connect() call, or later on getInputStream() if I don't call explicitly connect().
Using a raw thread instead of the asynctask worked for me, without changing anything else...
new Thread(() -> task.doInBackground())
More a workaround than a solution, but better than nothing.
Remove these 2 lines:
conn.setDoInput(true);
conn.connect(); // freezes here
When you do this:
HttpURLConnection conn = (HttpURLConnection) myFileUrl.openConnection();
int length = conn.getContentLength();
You are already connected. Calling conn.getContentLength() causes HttpURLConnection to make the connection, sends the request and fetches the response. You don't need to explicitly connect. You also don't need to call setDoInput(true) since that is the default setting.