I'm trying to send an image to a website using Java HTTP POST requests.
I'm using the base code used here Upload files from Java client to a HTTP server:
This is my modification:
String urlToConnect = "http://localhost:9000/upload";
File fileToUpload = new File("C:\\Users\\joao\\Pictures\\bla.jpg");
String boundary = Long.toHexString(System.currentTimeMillis()); // Just generate some unique random value.
URLConnection connection = new URL(urlToConnect).openConnection();
connection.setDoOutput(true); // This sets request method to POST.
connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
PrintWriter writer = null;
try {
writer = new PrintWriter(new OutputStreamWriter(connection.getOutputStream()));
writer.println("--" + boundary);
writer.println("Content-Disposition: form-data; name=\"picture\"; filename=\"bla.jpg\"");
writer.println("Content-Type: image/jpeg");
writer.println();
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(new FileInputStream(fileToUpload)));
for (String line; (line = reader.readLine()) != null;) {
writer.println(line);
}
} finally {
if (reader != null) try { reader.close(); } catch (IOException logOrIgnore) {}
}
writer.println("--" + boundary + "--");
} finally {
if (writer != null) writer.close();
}
// Connection is lazily executed whenever you request any status.
int responseCode = ((HttpURLConnection) connection).getResponseCode();
System.out.println(responseCode); // Should be 200
I get a 200 response code in the end, but the image is buggy, as in, random colors, which make me think it's an error in character encoding. I tried using UTF-8 as in the original example, but that just creates a corrupt image.
I am also 100% sure it's not a serverside problem, because I can use rest clients such as Advanced Rest Client/Postman and they can send an image with no problems.
Can you help me pinpoint what's wrong? Thank you.
import java.io.File;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.ContentBody;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.util.EntityUtils;
public class PostFile {
public static void main(String[] args) throws Exception {
HttpClient httpclient = new DefaultHttpClient();
httpclient.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
HttpPost httppost = new HttpPost("http://localhost:9000/upload");
File file = new File("C:\\Users\\joao\\Pictures\\bla.jpg"");
MultipartEntity mpEntity = new MultipartEntity();
ContentBody cbFile = new FileBody(file, "image/jpeg");
mpEntity.addPart("userfile", cbFile);
httppost.setEntity(mpEntity);
System.out.println("executing request " + httppost.getRequestLine());
HttpResponse response = httpclient.execute(httppost);
HttpEntity resEntity = response.getEntity();
System.out.println(response.getStatusLine());
if (resEntity != null) {
System.out.println(EntityUtils.toString(resEntity));
}
if (resEntity != null) {
resEntity.consumeContent();
}
httpclient.getConnectionManager().shutdown();
}
}
Use HttpClient to work out this code. Its always better to use stable libraries other than handling from scratch, unless there is something to be handled in custom way.
Today I run into the same issue, I wrote a little nodejs server supports just two routes, upload and download images.
Client should be a java class which sends a images payload via HTTP POST multipart/form-data standard to the server.
If you would like to know why HTTP POST multipart/form-data, please check out the answer from Ciro Santilli from this post: What does enctype='multipart/form-data' mean?
Luckily I found this nice and really good example code:
https://www.techcoil.com/blog/how-to-upload-a-file-via-a-http-multipart-request-in-java-without-using-any-external-libraries/
It shows how we can build up the payload of an multipart http body manuelly without any external lib, only little limitation from my perspective is, that it only handle a mulitpart body with one file.
Because I had no HTML page to sniff the generated POST payload, I used python to generate it and sniff it via wireshark.
Python3 code:
import requests
posturl = 'http://<server>:<port>/<path>'
files = {'image' : open('<file>', 'rb')}
r = requests.post(posturl, files = files)
Just for note: if we define the parameter files from the requests lib with an dict, it generates an mulipart/form-data content. http://docs.python-requests.org/en/master/user/advanced/#post-multiple-multipart-encoded-files
Wireshark shows everything very clear and finally I ended up with this for sending java:
HttpURLConnection conn =
(HttpURLConnection) new URL("http://<server>:<port>/<path>")).openConnection();
// some arbitrary text for multitext boundary
// only 7-bit US-ASCII digits max length 70
String boundary_string = "some radom/arbitrary text";
// we want to write out
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.addRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary_string);
// now we write out the multipart to the body
OutputStream conn_out = conn.getOutputStream();
BufferedWriter conn_out_writer = new BufferedWriter(new OutputStreamWriter(conn_out));
// write out multitext body based on w3 standard
// https://www.w3.org/Protocols/rfc1341/7_2_Multipart.html
conn_out_writer.write("\r\n--" + boundary_string + "\r\n");
conn_out_writer.write("Content-Disposition: form-data; " +
"name=\"image\"; " +
"filename=\""+ <File class instance>.getName() +"\"" +
"\r\n\r\n");
conn_out_writer.flush();
// payload from the file
FileInputStream file_stream = new FileInputStream(<File class instance>);
// write direct to outputstream instance, because we write now bytes and not strings
int read_bytes;
byte[] buffer = new byte[1024];
while((read_bytes = file_stream.read(buffer)) != -1) {
conn_out.write(buffer, 0, read_bytes);
}
conn_out.flush();
// close multipart body
conn_out_writer.write("\r\n--" + boundary_string + "--\r\n");
conn_out_writer.flush();
// close all the streams
conn_out_writer.close();
conn_out.close();
file_stream.close();
// execute and get response code
conn.getResponseCode();
To get the response from the POST just read the input stream accessed via getInputStream(), code snipped in the link.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With