I've been working with the Slack API in java and have been trying to get an HTTP method that can be used like my below example block of code. That code block works, but the issue is I need to also include a 200 response code, and can't figure out how to get it to work.
Basically, how can I, In Java, send an HTTP post and also tag on the 200 status code using the URL and the content?
Current code:
public void httpRequest(URL url, String content) {
try {
byte[] contentBytes = content.getBytes("UTF-8");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setRequestProperty("Accept-Charset", "UTF-8");
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("Content-Length", Integer.toString(contentBytes.length));
connection.setRequestProperty("Status", Integer.toString(200));
OutputStream requestStream = connection.getOutputStream();
requestStream.write(contentBytes, 0, contentBytes.length);
requestStream.close();
String response = "";
BufferedReader responseStream;
response = "" + ((HttpURLConnection) connection).getResponseCode();
try {
if (((HttpURLConnection) connection).getResponseCode() == 200) {
responseStream = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
} else {
responseStream = new BufferedReader(new InputStreamReader(((HttpURLConnection) connection).getErrorStream(), "UTF-8"));
}
response = responseStream.readLine();
responseStream.close();
} catch (NullPointerException ignored) {
}
} catch (IOException e) {
e.printStackTrace();
}
}
The call to setDoOutput(true) triggers a post, i.e. you do not need to add
connection.setRequestMethod("POST");
Adding a status header to the request is possible, as you have done, but typically one associates status codes with http responses, not requests. - And off course, adding such custom header would only make sense if the server was designed to use this information to anything.
See this big, and highly up-voted answer on java.net.HttpURLConnection.
Also, you have some problems relating to your response variable as well as the BufferedReader. You accidentally override the value you initially assigned to the response field, instead of concatening. Also, your readLine() should probably be in a loop:
String tmp;
while ((tmp = responseStream.readLine()) !=null){
response += tmp;
}
Related
This is my situation. I am calling the web authentication API with POST message. Upon success, it returns a token. Otherwise, it returns error message (json) specifying reasons (eg: "incorrect password", "account lock", etc), with response code 400, etc.
Sample error viewed from browser:
So, I manage to call, get and return the success message, but not when there is an error. Here's the pseudo code (I omit the redundant part. Basically focus on the 'catch' scope):
HttpURLConnection conn = null; //Must define outside as null?
try {
...
byte[] postDataBytes = ...
URL url = new URL(urlLogin);
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod( "POST" );
...
conn.getOutputStream().write(postDataBytes);
Reader in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
StringBuilder sb = new StringBuilder();
for (int c; (c = in.read()) >= 0;)
sb.append((char)c);
String response = sb.toString(); // Yeah I got this
return response;
}
catch(IOException ex){
//the variable ex doesn't tell anything about the response code
//neither the response message
//so i access the conn to get
//
try {
int responseCode = conn.getResponseCode();
return "code: " + responseCode; //somehow this line just doesn't work!
}
catch (Exception ex2){
}
}
To elaborate a bit, the IOException doesn't tell anything about the response. So I access the HttpURLConnection variable.
The
conn.getResponseCode() does return 400,
conn.getResponseMessage() does return "Bad Request", but NOT the error json message from server.
Any idea?
EDIT:
I just want to know, what is the correct way to get the response code/message during Exception/error.
getErrorStream() of HttpUrlConnection is probably what you are looking for.
Reader in = new BufferedReader(new InputStreamReader(conn.getErrorStream(), "UTF-8"));
// Do you response parsing here.
I'm trying to send some data from a JSP page to a PHP one (which should execute some code and return a success message).
I'm using this java function to make some tests:
public String excutePost(String targetURL, String urlParameters)
{
URL url;
HttpURLConnection connection = null;
try {
//Create connection
url = new URL(targetURL);
connection = (HttpURLConnection)url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
connection.setRequestProperty("Content-Length", "" +
Integer.toString(urlParameters.getBytes().length));
connection.setRequestProperty("Content-Language", "en-US");
connection.setUseCaches (false);
connection.setDoInput(true);
connection.setDoOutput(true);
//Send request
DataOutputStream wr = new DataOutputStream (
connection.getOutputStream ());
wr.writeBytes (urlParameters);
wr.flush ();
wr.close ();
//Get Response
InputStream is = connection.getInputStream();
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
String line;
StringBuffer response = new StringBuffer();
while((line = rd.readLine()) != null) {
response.append(line);
response.append('\r');
}
rd.close();
return response.toString();
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
if(connection != null) {
connection.disconnect();
}
}
}
String urlParameters =
"var=" + URLEncoder.encode("varcontent", "UTF-8");
out.println(excutePost("remoteurl",urlParameters));
Now if i run the page i get the response "null" and none of the code in the php page is executed.
Am I doing something wrong? How can I allow the php page to run the code in it?
Isn't a simple echo $_POST['var'] enough to send the data back to the jsp page?
EDIT: I tried to see if the php page is receiving something by writing the posted variable in a file. But nothing is written in it.
$file = 'debug.txt';
echo file_put_contents($file, $_POST['var']);
and here is the exception i'm getting..
java.net.SocketException: Connection reset
No, an echo is not enough. Put $_POST['var'] in say a text file and serve the updated text file (Edit the text file each time you need to keep track of $_POST['var']). Alternatively you can put it in some DB and check for changes.
What is the best way to use preemptive basic http authentication using HttpUrlConnection. (Assume for now I can't use HttpClient).
EDIT for clarification: I'm setting the un/pw correctly in the request header using Base64 encoding. Are there any additional flags or properties that need to be set, or is the fact that I'm setting the basic auth headers for the request all that is needed for preemptive basic auth?
If you are using Java 8 or later, java.util.Base64 is usable:
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
String encoded = Base64.getEncoder().encodeToString((username+":"+password).getBytes(StandardCharsets.UTF_8)); //Java 8
connection.setRequestProperty("Authorization", "Basic "+encoded);
Then use the connection as normal.
If you're using Java 7 or lower, you'll need a method to encode a String to Base64, such as:
byte[] message = (username+":"+password).getBytes("UTF-8");
String encoded = javax.xml.bind.DatatypeConverter.printBase64Binary(message);
Yes, that's all you have to do in order to use Basic Auth. The code above to set the Request Property should be done immediately after opening the connection and before getting the Input or Output streams.
Incidentally, in case someone else runs into the same, the android problem, is also present if you use org.apache.commons.codec.binary.Base64 and do Base64.encodeBase64String(). You need to do Base64.encodeBase64() and get a byte[] then construct the string.
It caught me offguard entirely that the results would be different for the line ending between those two methods.
You can use java.net.Authenticator to configure basic auth. globally for every request send by your application, see :
http://docs.oracle.com/javase/7/docs/technotes/guides/net/http-auth.html
http://developer.android.com/reference/java/net/Authenticator.html#getPasswordAuthentication()
you need to do this just copy paste it be happy
HttpURLConnection urlConnection;
String url;
// String data = json;
String result = null;
try {
String username ="danish.hussain#gmail.com";
String password = "12345678";
String auth =new String(username + ":" + password);
byte[] data1 = auth.getBytes(UTF_8);
String base64 = Base64.encodeToString(data1, Base64.NO_WRAP);
//Connect
urlConnection = (HttpURLConnection) ((new URL(urlBasePath).openConnection()));
urlConnection.setDoOutput(true);
urlConnection.setRequestProperty("Content-Type", "application/json");
urlConnection.setRequestProperty("Authorization", "Basic "+base64);
urlConnection.setRequestProperty("Accept", "application/json");
urlConnection.setRequestMethod("POST");
urlConnection.setConnectTimeout(10000);
urlConnection.connect();
JSONObject obj = new JSONObject();
obj.put("MobileNumber", "+97333746934");
obj.put("EmailAddress", "danish.hussain#dhl.com");
obj.put("FirstName", "Danish");
obj.put("LastName", "Hussain");
obj.put("Country", "BH");
obj.put("Language", "EN");
String data = obj.toString();
//Write
OutputStream outputStream = urlConnection.getOutputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream, "UTF-8"));
writer.write(data);
writer.close();
outputStream.close();
int responseCode=urlConnection.getResponseCode();
if (responseCode == HttpsURLConnection.HTTP_OK) {
//Read
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), "UTF-8"));
String line = null;
StringBuilder sb = new StringBuilder();
while ((line = bufferedReader.readLine()) != null) {
sb.append(line);
}
bufferedReader.close();
result = sb.toString();
}else {
// return new String("false : "+responseCode);
new String("false : "+responseCode);
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
I was having this problem too.
And Now I have solved this problem.
My code is :
URL url = new URL(stringUrl);
String authStr = "MyAPIKey"+":"+"Password";
System.out.println("Original String is " + authStr);
// encode data on your side using BASE64
byte[] bytesEncoded = Base64.encodeBase64(authStr .getBytes());
String authEncoded = new String(bytesEncoded);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestProperty("Authorization", "Basic "+authEncoded);
It may help many others.
Best of luck.
Regarding the Base64 encoding problem, I found this library: http://sourceforge.net/projects/migbase64/
I have not fully vetted it but I am using it for the Basic Authentication solution shown above (as well as for image encoding/decoding), and it works well. It provides a parameter for whether or not to include the newline.
I'm making an http GET request. It works in about 70% of my attempts. For some reason, I sometimes get no response string from a successful connection. I just setup a button in my app which keeps firing the code below. One call might fail to reply with a string, the next call works fine:
private onButtonClick() {
try {
doit();
} catch (Exception ex) {
...
}
}
public void doit() throws Exception {
URL url = new URL("http://www.example.com/service");
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
connection.setDoInput(true);
connection.setUseCaches(false);
connection.setAllowUserInteraction(false);
connection.setReadTimeout(30 * 1000);
connection.setRequestProperty("Connection", "Keep-Alive");
connection.setRequestProperty("Authorization",
"Basic " + Base64.encode("username" + ":" + "password"));
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line = "";
StringBuilder sb = new StringBuilder();
while ((line = in.readLine()) != null) {
sb.append(line);
}
in.close();
connection.disconnect();
// Every so often this prints an empty string!
System.out.println(sb.toString());
}
am I doing something wrong here? It seems like maybe I'm not closing the connection properly from the last call somehow and the response gets mangled or something? I am also calling doit() from multiple threads simultaneously, but I thought the contents of the method are thread-safe, same behavior though,
Thanks
Thanks
That method looks fine. It's reentrant, so calls shouldn't interfere with each other. It's probably a server issue, either deliberate throttling or just a bug.
EDIT: You can check the status code with getResponseCode.
For checking ResponseCode:
BufferedReader responseStream;
if (((HttpURLConnection) connection).getResponseCode() == 200) {
responseStream = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
} else {
responseStream = new BufferedReader(new InputStreamReader(((HttpURLConnection) connection).getErrorStream(), "UTF-8"));
}
For empty content resposneCode is 204. So if u can get empty body just add one more "if" with 204 code.
We also came across with the similar scenario, I came across the following solution for this issue:
- Setting up a user agent string on URLConnection object.
URLConnection conn = url.openConnection();
conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 4.01; Windows NT)");
more details
I'm having problem with sending XML-data using HTTP POST to an API.
If I send well formatted XML, I get an error message:
Server Exception: Cannot access a closed Stream
If the XML isn't well formatted, I get HTTP 500. And if I just send an empty string instead of a string with XML, I get back an error message: EMPTY REQUEST.
I don't have many ideas about what the error could be, but the connection works because the error message is returned in XML format. I'm just sending the XML data as a string. Is it possible that I am required to send an EOF or something in the end? And how do I do that in my Java code? Any other ideas about what the problem can be?
The API is made in .NET
Here is the Java code I'm using to POST the XML data:
Authenticator.setDefault(new MyAuthenticator());
String xmlRequestStatus =
"<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?><test><data>32</data></test>";
System.out.println(xmlRequestStatus);
String contentType = "text/xml";
String charset = "ISO-8859-1";
String request = null;
URL url = null;
HttpURLConnection connection = null;
OutputStream output = null;
InputStream response = null;
try {
url = new URL("http://127.0.0.1/test");
} catch (MalformedURLException e) {
e.printStackTrace();
}
try {
connection = (HttpURLConnection)url.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Accept-Charset", charset);
connection.setRequestProperty("Content-Type", contentType);
output = connection.getOutputStream();
output.write(request.getBytes("ISO-8859-1"));
if(output != null) try { output.close(); } catch (IOException e) {}
response = connection.getInputStream();
....
It looks fine and should work fine. The connection.setRequestMethod("POST"); is however entirely superfluous when you already did connection.setDoOutput(true);.
Since this error is coming straight from the .NET webservice hosted at localhost, are you sure that it is written without bugs? I don't do .NET, but Google learns me that it's related to MemoryStream. I'd concentrate on the .NET code and retest/debug it. Maybe those related SO questions may help.
You need to specify method POST by doing something like this,
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Length", "" + length);
Otherwise, it's treated as a GET and some server doesn't expect body with GET so the stream is closed.
Maybe close the OutputStream later in the control flow. So instead of this:
output.write(request.getBytes("ISO-8859-1"));
if(output != null) try { output.close(); } catch (IOException e) {}
response = connection.getInputStream();
Try this (and maybe add the flush)?
output.write(request.getBytes("ISO-8859-1"));
output.flush();
response = connection.getInputStream();
if(output != null) try { output.close(); } catch (IOException e) {}
Shouldn't it be <32 instead of <32?
It looks like request is initialized to null, but afterwards not set. Should it not be
output.write(xmlRequestStatus.getBytes("ISO-8859-1"));