Use of java.net.URLConnection
is asked about pretty often here, and the Oracle tutorial is too concise about it.
That tutorial basically only shows how to fire a GET request and read the response. It doesn't explain anywhere how to use it to among others perform a POST request, set request headers, read response headers, deal with cookies, submit a HTML form, upload a file, etc.
So, how can I use java.net.URLConnection
to fire and handle "advanced" HTTP requests?
There is also OkHttp, which is an HTTP client that’s efficient by default:
First create an instance of
OkHttpClient
:Then, prepare your
GET
request:finally, use
OkHttpClient
to send preparedRequest
:For more details, you can consult the OkHttp's documentation
if you are using http get please remove this line
I suggest you take a look at the code on kevinsawicki/http-request, its basically a wrapper on top of
HttpUrlConnection
it provides a much simpler API in case you just want to make the requests right now or you can take a look at the sources (it's not too big) to take a look at how connections are handled.Example: Make a
GET
request with content typeapplication/json
and some query parameters:First a disclaimer beforehand: the posted code snippets are all basic examples. You'll need to handle trivial
IOException
s andRuntimeException
s likeNullPointerException
,ArrayIndexOutOfBoundsException
and consorts yourself.Preparing
We first need to know at least the URL and the charset. The parameters are optional and depend on the functional requirements.
The query parameters must be in
name=value
format and be concatenated by&
. You would normally also URL-encode the query parameters with the specified charset usingURLEncoder#encode()
.The
String#format()
is just for convenience. I prefer it when I would need the String concatenation operator+
more than twice.Firing a HTTP GET request with (optionally) query parameters
It's a trivial task. It's the default request method.
Any query string should be concatenated to the URL using
?
. TheAccept-Charset
header may hint the server what encoding the parameters are in. If you don't send any query string, then you can leave theAccept-Charset
header away. If you don't need to set any headers, then you can even use theURL#openStream()
shortcut method.Either way, if the other side is a
HttpServlet
, then itsdoGet()
method will be called and the parameters will be available byHttpServletRequest#getParameter()
.For testing purposes, you can print the response body to stdout as below:
Firing a HTTP POST request with query parameters
Setting the
URLConnection#setDoOutput()
totrue
implicitly sets the request method to POST. The standard HTTP POST as web forms do is of typeapplication/x-www-form-urlencoded
wherein the query string is written to the request body.Note: whenever you'd like to submit a HTML form programmatically, don't forget to take the
name=value
pairs of any<input type="hidden">
elements into the query string and of course also thename=value
pair of the<input type="submit">
element which you'd like to "press" programmatically (because that's usually been used in the server side to distinguish if a button was pressed and if so, which one).You can also cast the obtained
URLConnection
toHttpURLConnection
and use itsHttpURLConnection#setRequestMethod()
instead. But if you're trying to use the connection for output you still need to setURLConnection#setDoOutput()
totrue
.Either way, if the other side is a
HttpServlet
, then itsdoPost()
method will be called and the parameters will be available byHttpServletRequest#getParameter()
.Actually firing the HTTP request
You can fire the HTTP request explicitly with
URLConnection#connect()
, but the request will automatically be fired on demand when you want to get any information about the HTTP response, such as the response body usingURLConnection#getInputStream()
and so on. The above examples does exactly that, so theconnect()
call is in fact superfluous.Gathering HTTP response information
HTTP response status:
You need a
HttpURLConnection
here. Cast it first if necessary.HTTP response headers:
HTTP response encoding:
When the
Content-Type
contains acharset
parameter, then the response body is likely text based and we'd like to process the response body with the server-side specified character encoding then.Maintaining the session
The server side session is usually backed by a cookie. Some web forms require that you're logged in and/or are tracked by a session. You can use the
CookieHandler
API to maintain cookies. You need to prepare aCookieManager
with aCookiePolicy
ofACCEPT_ALL
before sending all HTTP requests.Note that this is known to not always work properly in all circumstances. If it fails for you, then best is to manually gather and set the cookie headers. You basically need to grab all
Set-Cookie
headers from the response of the login or the firstGET
request and then pass this through the subsequent requests.The
split(";", 2)[0]
is there to get rid of cookie attributes which are irrelevant for the server side likeexpires
,path
, etc. Alternatively, you could also usecookie.substring(0, cookie.indexOf(';'))
instead ofsplit()
.Streaming mode
The
HttpURLConnection
will by default buffer the entire request body before actually sending it, regardless of whether you've set a fixed content length yourself usingconnection.setRequestProperty("Content-Length", contentLength);
. This may causeOutOfMemoryException
s whenever you concurrently send large POST requests (e.g. uploading files). To avoid this, you would like to set theHttpURLConnection#setFixedLengthStreamingMode()
.But if the content length is really not known beforehand, then you can make use of chunked streaming mode by setting the
HttpURLConnection#setChunkedStreamingMode()
accordingly. This will set the HTTPTransfer-Encoding
header tochunked
which will force the request body being sent in chunks. The below example will send the body in chunks of 1KB.User-Agent
It can happen that a request returns an unexpected response, while it works fine with a real web browser. The server side is probably blocking requests based on the
User-Agent
request header. TheURLConnection
will by default set it toJava/1.6.0_19
where the last part is obviously the JRE version. You can override this as follows:Use the User-Agent string from a recent browser.
Error handling
If the HTTP response code is
4nn
(Client Error) or5nn
(Server Error), then you may want to read theHttpURLConnection#getErrorStream()
to see if the server has sent any useful error information.If the HTTP response code is -1, then something went wrong with connection and response handling. The
HttpURLConnection
implementation is in older JREs somewhat buggy with keeping connections alive. You may want to turn it off by setting thehttp.keepAlive
system property tofalse
. You can do this programmatically in the beginning of your application by:Uploading files
You'd normally use
multipart/form-data
encoding for mixed POST content (binary and character data). The encoding is in more detail described in RFC2388.If the other side is a
HttpServlet
, then itsdoPost()
method will be called and the parts will be available byHttpServletRequest#getPart()
(note, thus notgetParameter()
and so on!). ThegetPart()
method is however relatively new, it's introduced in Servlet 3.0 (Glassfish 3, Tomcat 7, etc). Prior to Servlet 3.0, your best choice is using Apache Commons FileUpload to parse amultipart/form-data
request. Also see this answer for examples of both the FileUpload and the Servelt 3.0 approaches.Dealing with untrusted or misconfigured HTTPS sites
Sometimes you need to connect a HTTPS URL, perhaps because you're writing a web scraper. In that case, you may likely face a
javax.net.ssl.SSLException: Not trusted server certificate
on some HTTPS sites who doesn't keep their SSL certificates up to date, or ajava.security.cert.CertificateException: No subject alternative DNS name matching [hostname] found
orjavax.net.ssl.SSLProtocolException: handshake alert: unrecognized_name
on some misconfigured HTTPS sites.The following one-time-run
static
initializer in your web scraper class should makeHttpsURLConnection
more lenient as to those HTTPS sites and thus not throw those exceptions anymore.Last words
The Apache HttpComponents HttpClient is much more convenient in this all :)
Parsing and extracting HTML
If all you want is parsing and extracting data from HTML, then better use a HTML parser like Jsoup
There are 2 options you can go with HTTP URL Hits : GET / POST
GET Request :-
POST request :-
Initially I was misled by this article which favours
HttpClient
.Later I have been realized that
HttpURLConnection
is going to stay from this articleAs per the Google blog:
After reading this article and some other stack over flow questions, I am convinced that
HttpURLConnection
is going to stay for longer durations.Some of the SE questions favouring
HttpURLConnections
:On Android, make a POST request with URL Encoded Form data without using UrlEncodedFormEntity
HttpPost works in Java project, not in Android