I've read lots and tried lots relating to HTTP POSTS using HttpURLConnection and almost everything I come across has a similar structure which starts with these 3 lines:
url = new URL(targetURL);
connection = (HttpURLConnection)url.openConnection();
connection.setRequestMethod("POST");
When I try this I always get a "Connection Already Established" exception when calling setRequestMethod, which makes perfect sense as I'm clearly calling openConnection before setting the request type. Although reading the docs openConnection doesn't actually open the connection in theory.
There are several posts about this problem on SO such as this and this. I don't understand however why every piece of advice about how to write this code has these 3 lines in this order.
I'm guessing this code must work in most instances as someone must have tested it, so why doesn't this code work for me? How should I be writing this code?
I am aware these are other libraries I can use out there, I'm just wondering why this doesn't work.
Why the suspect code in the question has been duplicated all over the internet is something I can't answer. Nor can I answer why it seems to work for some people and not others. I can however answer the other question now, mainly thanks to this link that Luiggi pointed me to.
The key here is understanding the intricacies of the HttpURLConnection class. When first created the class defaults to a "GET" request method, so nothing needs to be changed in this instance. The following is rather unintuitive, but to set the request method to "POST" you should not call setRequestMethod("POST"), but rather setDoOutput(true) which implicitly sets the request method to post. Once you've done that you're good to go.
Below, I believe, is what a post method should look like. This is for posting json, but can obviously be altered for any other content type.
public static String doPostSync(final String urlToRead, final String content) throws IOException {
final String charset = "UTF-8";
// Create the connection
HttpURLConnection connection = (HttpURLConnection) new URL(urlToRead).openConnection();
// setDoOutput(true) implicitly set's the request type to POST
connection.setDoOutput(true);
connection.setRequestProperty("Accept-Charset", charset);
connection.setRequestProperty("Content-type", "application/json");
// Write to the connection
OutputStream output = connection.getOutputStream();
output.write(content.getBytes(charset));
output.close();
// Check the error stream first, if this is null then there have been no issues with the request
InputStream inputStream = connection.getErrorStream();
if (inputStream == null)
inputStream = connection.getInputStream();
// Read everything from our stream
BufferedReader responseReader = new BufferedReader(new InputStreamReader(inputStream, charset));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = responseReader.readLine()) != null) {
response.append(inputLine);
}
responseReader.close();
return response.toString();
}
As per https://stackoverflow.com/a/3324964/436524, you need to call connection.setDoOutput(true) for it to expect a POST request.
This makes your code like this:
url = new URL(targetURL);
connection = (HttpURLConnection)url.openConnection();
connection.setDoOutput(true);
Related
Line InputStream is = new GZIPInputStream (con.getInputStream ()); returns this "java.util.zip.ZipException: Not in GZIP format" exception. Does anyone know how to solve this?
my code:
private String getJsonFromRapidAPI(final String url) throws Exception {
final String token = generateSessionToken();
final HttpClient httpclient = new DefaultHttpClient();
final HttpGet httpget = new HttpGet(url);
String fileContents = null;
StringBuilder sb = new StringBuilder();
BufferedReader in = null;
if (inetAddress == null) {
inetAddress = InetAddress.getLocalHost();
}
final String serverIP = inetAddress.getHostAddress();
URL urlToCall = new URL(url);
HttpURLConnection con = (HttpURLConnection) urlToCall.openConnection();
con.setRequestProperty("Accept", "application/json");
con.setRequestProperty("Accept-Encoding", "gzip");
con.setRequestProperty("Authorization", token);
con.setRequestProperty("Customer-Ip", serverIP);
con.setRequestProperty("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36");
InputStream is = new GZIPInputStream(con.getInputStream());
StringWriter writer = new StringWriter();
IOUtils.copy(is, writer, "UTF-8");
return writer.toString();
}
Two issues here:
You can tell a server you want GZIP encoding. That doesn't mean it'll neccessarily comply.
As a consequence, your current code goes: Well, I asked for gzip, so I will assume i Must gunzip the stream. That's incorrect - you need to ask for gzip as you do, but you need to let 'should I GZipInputStream the response' depend on whether the server actually did that. To figure this out, use con.connect to actually connect (.getInputStream implies it, but now we need to fetch some response info before opening the inputstream so you need to explicitly connect now), and you can call ."gzip".equals(con.getContentEncoding()) to figure it out. If that is true, then wrap con.getInputStream() in GZIPInputStream. If it isn't, don't do that.
More generally you're abusing HttpURLConnection.
HttpURLConnection's job is to deal with the stream/processing of the data itself. That means headers like Transfer-Encoding, Host, and Accept-Encoding aren't 'your turf', you shouldn't be messing with this stuff. It needs to send 'hey, I can support gzip!' and it needs to wrap the response in a GZIPInputStream if the server says: "Great, okay, therefore I gzipped it for you!".
Unfortunately HttpURLConnection is extremely basic and messes up this distinction itself, for example it looks at the Transfer-Encoding header you set and will chunk sends (I think - oof, I haven't used this class in forever because its so bad).
If you have needs to make things even slightly complicated (and I'd say this qualifies), then stop using it. There's OkHttp from square. Java itself (Available in JDK11 and up, I think) calls HttpURLConnection obsolete and has replaced it - here is a tutorial, and even apache has HttpComponents but note that this is outdated and as with most apache java libraries, oof, it's bad API design. I wouldn't use that one, even if it is rather popular. It's still much better than HttpURLConnection though!
I have a short Android-Java client program which sends a basic information to bottle-python server with POST method. In the first version of code, server does not show anything. However, In the second version it works but I cannot understand what this additional line do because it has anything to do with posting content. I really appreciate if someone helps me figure this out.(There is nothing wrong with the server code since I can properly send request with python requests and my browsers).
This is the first version of client code:
String url = "http://192.168.1.23:8080/";
URL obj = new URL(url);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setDoOutput(true);
OutputStream os = con.getOutputStream();
PrintStream myPusher = new PrintStream(os );
myPusher.print("param1=hey");
Second version:
String url = "http://192.168.1.23:8080/";
URL obj = new URL(url);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setDoOutput(true);
OutputStream os = con.getOutputStream();
PrintStream myPusher = new PrintStream(os );
myPusher.print("param1=hey");
InputStream in= con.getInputStream(); //Nothing changed but only this additional line
Bottle(python) server:
#app.route('/', method="POST")
def hello():
print("it works")
name = request.forms.get("param1")
print(name)
return name
#app.route('/')
def hello():
i=0
print("it works")
run(app, host="192.168.1.23", port=8080)
With first client code server shows nothing.
With second code server shows:
it works
hey
192.168.1.24 - - [31/Dec/2018 17:10:28] "POST / HTTP/1.1" 200 3
Which is as I expected.
With your first code snippet the output stream is still open. So the server does not know if it got the complete request. Probably just closing the stream would work as well.
However, I would make at least a call to getResponseCode to see the outcome of the request.
Your java code seems incomplete for sending a post request.
I think by using this code, you can make it work for yourself.
The PrintStream is a buffered type, this means you should add a flush operation after each print(), or use println() instead.
I requested to send some parameters from java file using post method. I did
String urlParameters = "param1=a¶m2=b¶m3=c";
URL url = new URL("http://testing/index.jsp");
URLConnection conn = url.openConnection();
conn.setDoOutput(true);
OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream());
writer.write(urlParameters);
writer.flush();
But from receiver's end asks me to send it in body instead of url parameter. I am not sure what I am doing wrong. Please explain me how this code will work and what changes has to be done if I want to send info in request body.
i believe you either need to call the connect() method on the URLConnection at the end, or call a method that would cause the connect to be called for you, like fetching the resulting input stream.
Also you should think about what format the body should be in. Often people like to use standard formats like json, but you will have to decide that between you and the people implementing the server.
I am trying to make a HTTPS call using Java to a browser that uses the native login prompt.
http://blog.stevensanderson.com/2008/08/25/using-the-browsers-native-login-prompt/
Currently I'm using the below for HTTP and it works fine for other websites since I know the parameters to put in...however it fails for the above type of login (I am not sure how to capture the parameters...it's a login pop up..or if this is even the correct approach)....any ideas??..thanks
HttpUtility.sendPostRequest(requestURL, params);
String[] response = HttpUtility.readMultipleLinesRespone();
The server should respond to your first request with a WWW-Authenticate header and a status of 401. The header will contain details of the kind of authentication it's expecting.
Then you can try again after adding an Authorization header to your request in the correct format.
#alex: OK...I managed to make the HTTPS connection following your suggestion with this:
URL url = new URL("https://www.example.com/Login");
URLConnection urlConnection = url.openConnection();
urlConnection.setRequestProperty("Authorization", "Basic " + authString);
InputStream is = urlConnection.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
//then I read the input stream..
But when I tried to make another connection (say go to a different page after login) with this code in another method...taking URLConnection as the parameter:
//Below is in a method called account(URLConnection urlConnection)
URL url = new URL("https://www.example.com/account.aspx");
urlConnection = url.openConnection();
InputStream is = urlConnection.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
//again I read the input stream..
...it throws the below exception...same exception before logging in..how can I rectify?
Server returned HTTP response code: 401 for URL: https://www.example.com/account.aspx
You have probably moved on from this problem, but I recently had an issue that involved achieving functionality similar to the browser's native login prompt. I have solved it and written a post about it. Steven Sanderson's post was helpful for me too, in helping me understand certain concepts.
http://captaindanko.blogspot.com.au/2015/04/how-does-browsers-native-login-prompt.html
I am going to send sms via java. The problem is the sms gateway ask me to send in this format
http://push1.maccesssmspush.com/servlet/com.aclwireless.pushconnectivity.listen
ers.TextListener?userId=xxxxx&pass=xxxx&appid=xxxx&subappid=xxxx&msgtyp
e=1&contenttype=1&selfid=true&to=9810790590,9810549717&from=ACL&dlrre
q=true&text=This+is+a+test+msg+from+ACL&alert=
The problem how to call this from a java application is it possible or does it need special libraries? IS it using HttpURLConnection will do the job? Thank you.
A Sample code I have done below is this correct.
URL sendSms1 = new URL("http://push1.maccesssmspush.com/servlet/com.aclwireless.pushconnectivity.listen
ers.TextListener?userId=xxxxx&pass=xxxx&appid=xxxx&subappid=xxxx&msgtyp
e=1&contenttype=1&selfid=true&to=9810790590,9810549717&from=ACL&dlrre
q=true&text=This+is+a+test+msg+from+ACL&alert=");
URLConnection smsConn1 =
sendSms1.openConnection();
It's just an HTTP call, you don't need anything special in Java (or any modern language, I expect). Just build up the string as appropriate*, then make an HTTP request to that URL.
Take a peek at the Sun tutorial Reading from and Writing to a URLConnection if you need to pick up the basics of how to do the request part in Java. This uses the built-in classes, I'm sure there are dozens of libraries that handles connections in funky and/or convenient ways too, so by all means use one of those if you're familiar with it.
*One potential gotcha which might not have occurred to you - your query string arguments will have to be URL-encoded. So the + characters for example in the text parameter, are encoded spaces (which would have a different meaning in the URL). Likewise, if you wanted to send a ? character in one of your parameters, it would have to appear as %3F. Have a look at the accepted answer to HTTP URL Address Encoding in Java for an example of how you might build the URL string safely.
It looks like a simple GET request, you can use Apache HttpClient libarary for executing such a request. Have a look into a tutorial by Vogella here: http://www.vogella.de/articles/ApacheHttpClient/article.html for sample source code and explanations.
You can try to use java.net.URL library。
like this
// at this before you need to generate the urlString as "http://push1.maccesssmspush.com/servlet/com.aclwireless.pushconnectivity.listen
ers.TextListener?userId=xxxxx&pass=xxxx&appid=xxxx&subappid=xxxx&msgtyp
e=1&contenttype=1&selfid=true&to=9810790590,9810549717&from=ACL&dlrre
q=true&text=This+is+a+test+msg+from+ACL&alert="
URL url = new URL(urlString);
// send sms
URLConnection urlConnection = url.openConnection();// open the url
// and you, also can get the feedback if you want
BufferedReader br = new BufferedReader(new InputStreamReader(
urlConnection.getInputStream()));
URL url = new URL("http://smscountry.com/SMSCwebservice.asp");
HttpURLConnection urlconnection = (HttpURLConnection) url.openConnection();
[Edit]
urlconnection.setRequestMethod("POST");
urlconnection.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
urlconnection.setDoOutput(true);
OutputStreamWriter out = new OutputStreamWriter(urlconnection.getOutputStream());
out.write(postData);
out.close();
BufferedReader in = new BufferedReader(new InputStreamReader(urlconnection.getInputStream()));
String decodedString;
while ((decodedString = in.readLine()) != null) {
retval += decodedString;
}