private support for your internal/customer projects ... custom extensions and distributions ... versioned snapshots for indefinite support ... scalability guidance for your apps and Ajax/Comet projects ... development services from 1 day to full product delivery
The simpler way to perform a HTTP request is the following:
ContentResponse response = httpClient.GET("http://domain.com/path?query");
Method HttpClient.GET(...)
performs a HTTP GET request to the given URI and returns a
ContentResponse
when the request/response conversation completes successfully.
The ContentResponse
object contains the HTTP response information: status code, headers
and possibly a content. The content length is limited by default to 2 MiB; for larger content see
Response Content Handling.
If you want to customize the request, for example by issuing a HEAD request instead of a GET, and simulating a browser user agent, you can do it in this way:
ContentResponse response = httpClient.newRequest("http://domain.com/path?query") .method(HttpMethod.HEAD) .agent("Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:17.0) Gecko/20100101 Firefox/17.0") .send();
This is a shorthand for:
Request request = httpClient.newRequest("http://domain.com/path?query"); request.method(HttpMethod.HEAD); request.agent("Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:17.0) Gecko/20100101 Firefox/17.0"); ContentResponse response = request.send();
You first create a request object using httpClient.newRequest(...)
, and then you customize it
using the fluent API style (that is, chained invocation of methods on the request object). When the request object
is customized, you call Request.send()
that produces the ContentResponse
when
the request/response conversation is complete.
Simple POST requests also have a shortcut method:
ContentResponse response = httpClient.POST("http://domain.com/entity/1") .param("p", "value") .send();
The POST request is sent with the application/x-www-form-urlencoded
content type, and POST
parameter values are automatically URL-encoded.
Jetty HTTP client automatically follows redirects, so automatically handles the typical web pattern POST/Redirect/GET, and the response object contains the content of the response of the GET request. Following redirects is a feature that you can enable/disable on a per-request basis or globally.
File uploads also require one line, and make use of JDK 7′s java.nio.file
classes:
ContentResponse response = httpClient.newRequest("http://domain.com/upload") .file(Paths.get("file_to_upload.txt"), "text/plain") .send();
It is possible to impose a total timeout for the request/response conversation using the
Request.timeout(...)
method, in this way:
ContentResponse response = httpClient.newRequest("http://domain.com/path?query") .timeout(5, TimeUnit.SECONDS) .send();
In the example above, when the 5 seconds expire, the request is aborted and a
java.util.concurrent.TimeoutException
is thrown.
So far we have shown how to use Jetty HTTP client in a blocking style, that is the thread that issues the request blocks until the request/response conversation is complete. In this section we will look at Jetty HTTP client asynchronous, non-blocking, APIs that are perfectly suited for large content downloads, for parallel processing of requests/responses and in all those cases where performance and efficient thread and resource utilization is a key factor.
A simple asynchronous GET request can be written in this way:
httpClient.newRequest("http://domain.com/path") .send(new Response.CompleteListener() { @Override public void onComplete(Result result) { // Your logic here } });
Method Request.send(Response.CompleteListener)
returns void and does not block; the
Response.CompleteListener
provided as a parameter is notified when the request/response conversation is
complete, and the Result
parameter allows you to access the response object.
You can write the same code using JDK 8′s lambda expressions:
httpClient.newRequest("http://domain.com/path") .send((result) -> { /* Your logic here */ });
You can impose a total timeout for the request/response conversation in the same way used by the synchronous API:
Request request = httpClient.newRequest("http://domain.com/path") .timeout(3, TimeUnit.SECONDS) .send(new Response.CompleteListener() { @Override public void onComplete(Result result) { // Your logic here } });
The example above will impose a total timeout of 3 seconds on the request/response conversation.
The HTTP client APIs use listeners extensively to provide hooks for all possible request and response events, and with JDK 8′s lambda expressions they’re even more fun to use:
httpClient.newRequest("http://domain.com/path") // Add request hooks .onRequestQueued((request) -> { ... }) .onRequestBegin((request) -> { ... }) ... // More request hooks available // Add response hooks .onResponseBegin((response) -> { ... }) .onResponseHeaders((response) -> { ... }) .onResponseContent((response, buffer) -> { ... }) ... // More response hooks available .send((result) -> { ... });
This makes Jetty HTTP client suitable for HTTP load testing because, for example, you can accurately time every step of the request/response conversation (thus knowing where the request/response time is really spent).
Have a look at the
Request.Listener
class to know about request events, and to the
Response.Listener
class to know about response events.
Jetty HTTP client provides a number of utility classes off the shelf to handle request content.
You can provide request content as String
, byte[]
, ByteBuffer
,
java.nio.file.Path
, InputStream
, and provide your own implementation of
org.eclipse.jetty.client.api.ContentProvider
. Here’s an example that provides the
request content using java.nio.file.Paths
:
ContentResponse response = httpClient.newRequest("http://domain.com/upload") .file(Paths.get("file_to_upload.txt"), "text/plain") .send();
This is equivalent to using the PathContentProvider
utility class:
ContentResponse response = httpClient.newRequest("http://domain.com/upload") .content(new PathContentProvider(Paths.get("file_to_upload.txt")), "text/plain") .send();
Alternatively, you can use FileInputStream
via the
InputStreamContentProvider
utility class:
ContentResponse response = httpClient.newRequest("http://domain.com/upload") .content(new InputStreamContentProvider(new FileInputStream("file_to_upload.txt")), "text/plain") .send();
Since InputStream
is blocking, then also the send of the request will block if the
input stream blocks, even in case of usage of the asynchronous HttpClient
APIs.
If you have already read the content in memory, you can pass it as a byte[]
using the
BytesContentProvider
utility class:
byte[] bytes = ...; ContentResponse response = httpClient.newRequest("http://domain.com/upload") .content(new BytesContentProvider(bytes), "text/plain") .send();
If the request content is not immediately available, but your application will be notified of the
content to send, you can use DeferredContentProvider
in this way:
DeferredContentProvider content = new DeferredContentProvider(); httpClient.newRequest("http://domain.com/upload") .content(content) .send(new Response.CompleteListener() { @Override public void onComplete(Result result) { // Your logic here } }); // Content not available yet here ... // An event happens, now content is available byte[] bytes = ...; content.offer(ByteBuffer.wrap(bytes)); ... // All content has arrived content.close();
While the request content is awaited and consequently uploaded by the client application, the server
may be able to respond (at least with the response headers) completely asynchronously.
In this case, Response.Listener
callbacks will be invoked before the request is fully sent.
This allows fine-grained control of the request/response conversation: for example the server may reject
contents that are too big, send a response to the client, which in turn may stop the content upload.
Another way to provide request content is by using an OutputStreamContentProvider
, which
allows applications to write request content when it is available to the OutputStream
provided by
OutputStreamContentProvider
:
OutputStreamContentProvider content = new OutputStreamContentProvider(); // Use try-with-resources to close the OutputStream when all content is written try (OutputStream output = content.getOutputStream()) { client.newRequest("localhost", 8080) .content(content) .send(new Response.CompleteListener() { @Override public void onComplete(Result result) { // Your logic here } }); ... // Write content writeContent(output); } // End of try-with-resource, output.close() called automatically to signal end of content
Jetty HTTP client allows applications to handle response content in different ways.
The first way is to buffer the response content in memory; this is done when using the blocking APIs (see
Blocking APIs) and the content is buffered within a ContentResponse
up to
2 MiB.
If you want to control the length of the response content (for example limiting to values smaller than the
default of 2 MiB), then you can use a
org.eclipse.jetty.client.util.FutureResponseListener
in this way:
Request request = httpClient.newRequest("http://domain.com/path"); // Limit response content buffer to 512 KiB FutureResponseListener listener = new FutureResponseListener(request, 512 * 1024); request.send(listener); ContentResponse response = listener.get(5, TimeUnit.SECONDS);
If the response content length is exceeded, the response will be aborted, and an exception will be thrown
by method get()
.
If you are using the asynchronous APIs (see Asynchronous APIs), you can use the
BufferingResponseListener
utility class:
httpClient.newRequest("http://domain.com/path") // Buffer response content up to 8 MiB .send(new BufferingResponseListener(8 * 1024 * 1024) { @Override public void onComplete(Result result) { if (!result.isFailed()) { byte[] responseContent = getContent(); // Your logic here } } });
The second way is the most efficient (because it avoids content copies) and allows you to specify a
Response.ContentListener
, or a subclass, to handle the content as soon as it arrives:
ContentResponse response = httpClient .newRequest("http://domain.com/path") .send(new Response.Listener.Empty() { @Override public void onContent(Response response, ByteBuffer buffer) { // Your logic here } });
The third way allows you to wait for the response and then stream the content using the
InputStreamResponseListener
utility class:
InputStreamResponseListener listener = new InputStreamResponseListener(); httpClient.newRequest("http://domain.com/path") .send(listener); // Wait for the response headers to arrive Response response = listener.get(5, TimeUnit.SECONDS); // Look at the response if (response.getStatus() == 200) { InputStream responseContent = listener.getInputStream(); // Your logic here }
See an error or something missing? Contribute to this documentation at Github!