Why the code throws "Cannot write output after reading input" error? - java

Please check the code below. What the code does is use firstHttpConn to check the response code and open secondHttpConn. If the response code is 401, add a basic auth header to secondHttpConn. Then post the data and read the response.
However, the code throws Cannot write output after reading input error. I checked other questions on Stack Overflow like this one and I am sure I did not make the same mistakes.
//I hate using Java 6 and HttpURLConnection, but the code is for a very old system.
private static XmlObject callWebService(String soapMessage, String webServiceEndpoint, String soapAction) throws Exception {
XmlObject resultXMLObject;
HttpURLConnection firstHttpConn = null;
HttpURLConnection secondHttpConn = null;
try {
byte[] streamoutByteArray = soapMessage.getBytes("UTF-8");
URL url = new URL(webServiceEndpoint);
firstHttpConn = (HttpURLConnection) url.openConnection();
firstHttpConn.connect();
if (firstHttpConn.getResponseCode() == 401) {
firstHttpConn.disconnect();
secondHttpConn = (HttpURLConnection) url.openConnection();
secondHttpConn.setRequestProperty("Authorization", "Basic " + getBasicAuth());
} else {
firstHttpConn.disconnect();
secondHttpConn = (HttpURLConnection) url.openConnection();
}
secondHttpConn.setConnectTimeout(30000);
secondHttpConn.setReadTimeout(300000);
secondHttpConn.setRequestProperty("Content-Length", String.valueOf(streamoutByteArray.length));
secondHttpConn.setRequestProperty("Content-Type", "text/xml; charset=UTF-8);
secondHttpConn.setRequestProperty("SOAPAction", soapAction);
secondHttpConn.setRequestMethod("POST");
secondHttpConn.setDoOutput(true);
secondHttpConn.setDoInput(true);
OutputStream out = secondHttpConn.getOutputStream();
out.write(streamoutByteArray);
out.close();
//Line 238 below.
InputStreamReader isr = new InputStreamReader(secondHttpConn.getInputStream());
BufferedReader in = new BufferedReader(isr);
String inputLine;
StringBuffer sb = new StringBuffer();
while ((inputLine = in.readLine()) != null)
sb.append(inputLine).append("\n");
in.close();
resultXMLObject = XmlObject.Factory.parse(sb.toString());
} finally {
if (firstHttpConn != null)
firstHttpConn.disconnect();
if (secondHttpConn != null)
secondHttpConn.disconnect();
}
return resultXMLObject;
}
The log:
Caused By: java.net.ProtocolException: Cannot write output after reading input.
at weblogic.net.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:271)
at org.company.member.esb.webservice.WebServiceClient.callWebService(WebServiceClient.java:238)
at org.company.member.esb.webservice.WebServiceClient.invokeWebserviceV01(WebServiceClient.java:132)
at sun.reflect.GeneratedMethodAccessor711.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
Truncated. see log file for complete stacktrace
Anyone knows why? Thanks.

You're not running the code you pasted here. You can see the lines do not match, as there is HttpURLConnection.getOutputStream in the stack trace, but you claim
//Line 238 below.
InputStreamReader isr = new InputStreamReader(secondHttpConn.getInputStream());
so code is different for stack trace and your paste.
I don't see a problem with the code you've pasted here.

Related

POST in JAVA using HttpURLConnection getting a HTTP response code 400

I'm pretty new to making HTTP connections and working with API's in Java, so I'm not sure where the problem lies. When I send out a POST connection request in order to send a JSON formatted String of text to the other side, I get an error back along with a 400 response code. When I look up that code, it seems my connection isn't properly formatted. Code is below, along with the error message. Please help! Thanks!
public void sendToAPI(String urlPass, String param) throws IOException {
URL url = new URL(urlPass);
HttpURLConnection connectionOut = (HttpURLConnection) url.openConnection();
connectionOut.setRequestMethod("POST");
connectionOut.setConnectTimeout(5000);
connectionOut.setReadTimeout(5000);
connectionOut.setRequestProperty("Content-Type", "application/json");
connectionOut.setRequestProperty("Content-Length", Integer.toString(param.length()));
connectionOut.setDoOutput(true);
connectionOut.setDoInput(true);
connectionOut.connect();
DataOutputStream stream = new DataOutputStream(connectionOut.getOutputStream());
stream.writeUTF(param);
stream.flush();
stream.close();
int responsecode = connectionOut.getResponseCode();
if(responsecode != 200) {
System.out.println("Response Code is " + responsecode);
}
BufferedReader in = new BufferedReader(
new InputStreamReader(connectionOut.getInputStream()));
String output;
StringBuffer response = new StringBuffer();
while ((output = in.readLine()) != null) {
response.append(output);
}
in.close();
//printing result from response
System.out.println(response.toString());
}
Response Code is 400
Exception in thread "main" java.io.IOException: Server returned HTTP response code: 400 for URL:XXX
u can try this code:
InputStream inputStream;
if (responseCode == 200) {
inputStream = con.getInputStream();
} else {
inputStream = con.getErrorStream();
}
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder builder = new StringBuilder();
String lines;
while ((lines = reader.readLine()) != null) {
builder.append(lines);
builder.append(System.getProperty("line.separator"));
}
String retStr = builder.toString().trim();
reader.close();
System.out.println("retStr: " + retStr);
So after playing around with the DataOutputStream, I replaced the below code:
DataOutputStream stream = new DataOutputStream(connectionOut.getOutputStream());
stream.writeUTF(param);
With another example I found online:
OutputStream os = connectionOut.getOutputStream();
os.write(param.getBytes());
os.flush();
os.close();
I'm not sure yet why, but this suddenly got the proper response code I was looking for, so the format it was sent in matched what they requested. Thanks for all responses.

How to replicate curl command using java?

Precisely said I want to perform below curl action which returns json with java:
curl -H 'Client-ID: ahh_got_ya' -X GET 'https://api.twitch.tv/helix/streams'
This works just fine in linux shell.
below is my script trying to do above curl using java json:
{String urly = "https://api.twitch.tv/helix/streams";
URL obj = new URL(urly);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("GET");
con.setRequestProperty("Content-Type","application/json");
con.setRequestProperty("Client-ID","Ahh_got_ya");
con.setDoOutput(true);
DataOutputStream wr = new DataOutputStream(con.getOutputStream());
wr.writeBytes("");
wr.flush();
wr.close();
int responseCode = con.getResponseCode();
System.out.println("Response Code : " + responseCode);
BufferedReader iny = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String output;
StringBuffer jsonres = new StringBuffer();
while ((output = iny.readLine()) != null) {
jsonres.append(output);
}
iny.close();
//printing result from response
System.out.println(response.toString());
}
I am getting: java.io.FileNotFoundException: https://api.twitch.tv/helix/streams Response Code : 404
All replies are much appreciated.
Almost there! You are doing a GET call and do not need to make the connection writeable -- since you are not going to post. You need to remove that section there. Also - to get exactly what your curl call is doing, remove the Content-Type - since it is not used in the curl call. So your code adjusted should be:
{
String urly = "https://api.twitch.tv/helix/streams";
URL obj = new URL(urly);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
//only 2 headers from cURL call
con.setRequestMethod("GET");
con.setRequestProperty("Client-ID","Ahh_got_ya");
int responseCode = con.getResponseCode();
System.out.println("Response Code : " + responseCode);
BufferedReader iny = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String output;
StringBuffer jsonres = new StringBuffer();
while ((output = iny.readLine()) != null) {
jsonres.append(output);
}
iny.close();
//printing result from response
System.out.println(response.toString());
}
The reason for the 404 is if your request does not match what the service endpoint is expecting. Sending a POST request or other types of non-expect stuff will result is a request that does not match. Remove the extra output stuff and give it a go!
The way you state your question is a bit weird. But I assume you want to let a Java program make a cURL call of a JSON file. Now your linux terminal talks BASH not Java. So here is step 1.
You have to use a library.
Options are java.net.URL and/or java.net.URLConnection.
So #include one or either of those.
URL url = new URL("https://api.twitch.tv/helix/streams");
try (BufferedReader reader = new BufferedReader(new
InputStreamReader(url.openStream(), "UTF-8"))) {
for (String line; (line = reader.readLine()) != null;) {
System.out.println(line);
}
}
https://docs.oracle.com/javase/tutorial/networking/urls/readingWriting.html
Another thing you could mean is you want Java to generate JSON and access cURL trough Bash which isn't something I would advise anyone to do. If you feel like you have to it would be something like this.
public class ExecuteShellCommand {
public String executeCommand(String command) {
With the string set to cURL

OutputStream os = con.getOutputStream() throws NullPointerException

I am trying to build an android app for a website and I need to post some value to this page first.
Here is my code:
private void sendPOST(String user,String pass) throws IOException {
String POST_PARAMS = "username="+user+"&password="+pass;
URL obj = new URL("http://xx.xx.xx.xx/mysite/test.php");
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("User-Agent", "Mozilla/5.0");
//----------------------------------------------------------- For POST only - START---------------------------------------------
con.setDoOutput(true);
OutputStream os = con.getOutputStream();
os.write(POST_PARAMS.getBytes());
os.flush();
os.close();
// ------------------------------------------------------------For POST only - END----------------------------------------------------
int responseCode = con.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) { //success
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
// print result
Toast.makeText(getApplicationContext(), response.toString()==""?"No Result":response.toString(), Toast.LENGTH_LONG).show();
} else {
Toast.makeText(getApplicationContext(),"POST request failed", Toast.LENGTH_LONG).show();
}
}
when this line is executed OutputStream os = con.getOutputStream();
a null exception occurs.
I am unable to proceed further. Please suggest what i must do to remove this exception.
put your delevelopment server in another locatation other than localhost (try using the real IP, something like: 192.168.0.1).
sometimes you will receive a successfull connection from HttpUrlConnection.openConnection() (it returns non null object) and this not guarantee the subsequents calls to success. In other words, when you call con.getOutputStream() it throws an exception no matter if con is non-null.
It's the old question but I might have to answer on it because I have face to it today. When you ping http (instead https) have to put in manifest -> application: android:usesCleartextTraffic="true"
I think this would helped you years ago...
try(OutputStream os = con.getOutputStream()) {
byte[] input = POST_PARAMS.getBytes("utf-8");
os.write(input, 0, input.length);
}
maybe you should try to "connect" first before doing anything with your created HttpURLConnection con.
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.connect();
do more stuff with con...
I hope this helps you :)
URL obj = new URL("http://xx.xx.xx.xx/mysite/test.php");
URL Class object "obj" can't reach to your mentioned URL properly.
Try this instead:
URL obj = new URL("http://"+"xx.xx.xx.xx/mysite/test.php");

Android: not getting xml out of http get request with basic authentication

My goal is to get the xml from an API. The API uri I use, including parameters is http://webservices.ns.nl/ns-api-treinplanner?fromStation=Roosendaal&toStation=Eindhoven. I am given a username and password, for what I think probably is basic authorization.
I tried various things like something with an Authenticator, the format http://username:password#webservices.ns.nl/ns-api-treinplanner, but at the end of a lot of SO searching I ended up with something with a setRequestProperty with the basic authorization.
I put the code into an AsyncTask which seems to work correctly so I will just put the code from inside doInBackground in here.
As the java FileNotFoundException I first got didn't give me much information, I found out how to use the getErrorStream to find out more.
InputStream in;
int resCode;
try {
URL url = new URL("http://webservices.ns.nl/ns-api-treinplanner?fromStation=Roosendaal&toStation=Eindhoven");
String userCredentials = "username:password";
String encoding = new String(android.util.Base64.encode(userCredentials.getBytes(), Base64.DEFAULT));
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestProperty("Authorization", "Basic " + encoding);
urlConnection.setRequestMethod("GET");
urlConnection.setDoOutput(true);
try {
resCode = urlConnection.getResponseCode();
if (resCode == HttpURLConnection.HTTP_OK) {
Log.i("rescode","ok");
in = urlConnection.getInputStream();
} else {
Log.i("rescode","not ok");
in = urlConnection.getErrorStream();
}
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(in));
StringBuilder stringBuilder = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
stringBuilder.append(line).append("\n");
}
bufferedReader.close();
return stringBuilder.toString();
}
finally{
urlConnection.disconnect();
}
}
catch(Exception e) {
Log.e("ERROR", e.getMessage(), e);
return null;
}
Then, in onPostExecute I print the response, but the response I get is
<?xml version="1.0"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" soap:encodingStyle="http://www.w3.org/2003/05/soap-encoding">
<soap:Header></soap:Header>
<soap:Body><soap:Fault>
<faultcode>soap:Server</faultcode>
<faultstring>006:No customer found for the specified username and password</faultstring></soap:Fault>
</soap:Body></soap:Envelope>
This is of course not right, it should give a full xml of in this case a train voyage recommendation.
I tested with my browsers, and also using a HTTP request tool called Postman which returned the correct xml so all the uri's, parameters, username and password are correct.
The encoding used is wrong. The base64 encoding used randomly returns whitespaces in the middle, adding encoding = encoding.replaceAll("\\s+",""); actually fixed it.

Grabbing JSON works from one link, not from another

I'm doing a simple JSON grab from two links with the same code. I'm doing it two separate times, so the cause of my issue isn't because they're running into each other or something.
Here is my code:
#Override
protected String doInBackground(Object... params) {
try {
URL weatherUrl = new URL("my url goes here");
HttpURLConnection connection = (HttpURLConnection) weatherUrl
.openConnection();
connection.connect();
responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
InputStream inputStream = connection.getInputStream();
Reader reader = new InputStreamReader(inputStream);
int contentLength = connection.getContentLength();
char[] charArray = new char[contentLength];
reader.read(charArray);
String responseData = new String(charArray);
Log.v("test", responseData);
When I try this with:
http://www.google.com/calendar/feeds/developer-calendar#google.com/public/full?alt=json
I get an error of having an array lenth of -1
For this link:
http://api.openweathermap.org/data/2.5/weather?id=5815135
It returns fine and I get a log of all of the JSON. Does anyone have any idea why?
Note: I tried stepping through my code in debug mode, but I couldn't catch anything. I also downloaded a Google chrome extension for parsing json in the browser and both urls look completely valid. I'm out of ideas.
Log this: int contentLength = connection.getContentLength();
I don't see the google url returning a content-length header.
If you just want String output from a url, you can use Scanner and URL like so:
Scanner s = new Scanner(new URL("http://www.google.com").openStream(), "UTF-8").useDelimiter("\\A");
out = s.next();
s.close();
(don't forget try/finally block and exception handling)
The longer way (which allows for progress reporting and such):
String convertStreamToString(InputStream is) throws UnsupportedEncodingException {
BufferedReader reader = new BufferedReader(new
InputStreamReader(is, "UTF-8"));
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null)
sb.append(line + "\n");
} catch (IOException e) {
// Handle exception
} finally {
try {
is.close();
} catch (IOException e) {
// Handle exception
}
}
return sb.toString();
}
}
and then call String response = convertStreamToString( inputStream );

Categories