Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Difference between revisions of "Jetty/Tutorial/HttpClient"

 
(5 intermediate revisions by 2 users not shown)
Line 1: Line 1:
 
{{Jetty Tutorial
 
{{Jetty Tutorial
 
| introduction =
 
| introduction =
 +
 +
{{Jetty Redirect|http://www.eclipse.org/jetty/documentation/current/http-client-api.html}}
 +
 
HttpClient is the Jetty component that allows to make requests and interpret responses to HTTP servers.
 
HttpClient is the Jetty component that allows to make requests and interpret responses to HTTP servers.
  
Line 9: Line 12:
 
Instead, the request is sent concurrently to your code, and the response is interpreted also concurrently with your code.
 
Instead, the request is sent concurrently to your code, and the response is interpreted also concurrently with your code.
  
The HttpClient API offers you '''callbacks''' to interact with the request-response lifecycle.  
+
The HttpClient API offers you ''callbacks'' to interact with the request-response lifecycle.  
 
These callbacks will be called by the HttpClient implementation to allow further actions to be performed during each request-response event.
 
These callbacks will be called by the HttpClient implementation to allow further actions to be performed during each request-response event.
  
 +
A request-response unit is called ''exchange'', and represent the exchange of information with the HTTP server.
 +
 +
There are two main classes in the HttpClient API:
 +
* <tt>[http://download.eclipse.org/jetty/stable-7/apidocs/org/eclipse/jetty/client/HttpClient.html org.eclipse.jetty.client.HttpClient]</tt>, which manages the thread pooling, the proxy setting, the authentication settings, the connector type (blocking or non-blocking), the SSL settings and the timeouts. <tt>HttpClient</tt> manages the configuration that does not depend on a particular exchange.
 +
* <tt>[http://download.eclipse.org/jetty/stable-7/apidocs/org/eclipse/jetty/client/HttpExchange.html org.eclipse.jetty.client.HttpExchange]</tt>, which is the base class that you normally have to subclass that represent the exchange with the HTTP server, and manages HTTP method, the request URI, HTTP headers, request content, HTTP response code, HTTP response headers and response content.
 +
 +
== HttpClient Setup ==
 +
Before exchanging requests/responses with the HTTP server, you need to setup the HttpClient and then start it:
 +
 +
<source lang="java">
 +
HttpClient client = new HttpClient();
 +
client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
 +
client.start();
 +
</source>
 +
 +
You can also choose to setup the maximum number of connections per address (connections are pooled up to that maximum number), or to specify the thread pool, or the timeout:
 +
 +
<source lang="java">
 +
HttpClient client = new HttpClient();
 +
client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
 +
client.setMaxConnectionsPerAddress(200); // max 200 concurrent connections to every address
 +
client.setThreadPool(new QueuedThreadPool(250)); // max 250 threads
 +
client.setTimeout(30000); // 30 seconds timeout; if no server reply, the request expires
 +
client.start();
 +
</source>
 +
 +
Remember to configure the HttpClient before starting it, or the settings will not have effect.
 +
 +
Since HttpClient does not have any settings related to a particular address, it can be used to exchange requests/responses with several HTTP servers.
 +
You normally need one HttpClient instance for all your needs, even if you plan to connect to multiple HTTP servers.
 +
 +
== Asynchronous Exchanges ==
 +
Once the HttpClient has been setup, exchanges may be initiated by using the <tt>HttpClient.send(HttpExchange exchange)</tt> method.
 +
 +
The exchange must be configured with two mandatory fields: the address to connect to, and the request URI, or equivalently with an absolute URL:
 +
 +
<source lang="java">
 +
HttpExchange exchange = new HttpExchange();
 +
 +
// Optionally set the HTTP method
 +
exchange.setMethod("POST");
 +
 +
exchange.setAddress(new Address("ping.host.com", 80));
 +
exchange.setURI("/ping");
 +
// Or, equivalently, this:
 +
exchange.setURL("http://ping.host.com/ping");
 +
 +
client.send(exchange);
 +
 +
System.out.println("Exchange sent");
 +
</source>
 +
 +
The most important thing to remember is that the <tt>send()</tt> method returns immediately after dispatching the exchange to a thread pool for execution, so the <tt>System.out</tt> is executed immediately after the <tt>send()</tt> method. It may be well true that the <tt>System.out</tt> is executed well before the exchange is actually executed, as well as it may be well true that the <tt>System.out</tt> is executed after the exchange is completely executed (when even the request has been received).
 +
 +
Beware of not assuming anything about the status of the exchange just because you called <tt>send()</tt>.
 +
 +
== Controlling the Exchange Progress ==
 +
Because we used the HttpExchange class directly, without subclassing it, we have neither control nor notifications about the status of the exchange.
 +
The <tt>HttpExchange</tt> class exposes the following callback methods to be overridden to be notified of the status of the exchange:
 +
* <tt>onRequestCommitted()</tt>, called when the request line and the request headers have been sent to the HTTP server.
 +
* <tt>onRequestComplete()</tt>, called when the request content has been sent to the HTTP server.
 +
* <tt>onResponseStatus(Buffer httpVersion, int statusCode, Buffer statusMessage)</tt>, called when the response line has been processed; the three parameters hold, respectively, the HTTP version string (e.g. "HTTP/1.1"), the response status code (e.g. 200) and the response status message (e.g. "OK").
 +
* <tt>onResponseHeader(Buffer name, Buffer value)</tt>, called for each response header that has been processed; the parameters hold the name of the header (e.g. "Content-Length") and the value of the header (e.g. "16384").
 +
* <tt>onResponseHeaderComplete()</tt>, called when all response headers have been processed.
 +
* <tt>onResponseContent(Buffer content)</tt>, called multiple times for each chunk of the response content; the parameter holds the chunk of the content that has been received.
 +
* <tt>onResponseComplete()</tt>, called when the response content has been completely received.
 +
 +
Additionally four more methods can be overridden to be notified of non-normal conditions:
 +
* <tt>onConnectionFailed(Throwable x)</tt>, called when it is not possible to connect to the address specified in the exchange; the parameter holds the exception received while trying to connect.
 +
* <tt>onException(Throwable x)</tt>, called when a connection was possible, but an error happened later; the parameter holds the exception happened.
 +
* <tt>onExpire()</tt>, called when the server did not respond before the timeout configured in the HttpClient.
 +
* <tt>onRetry()</tt>, called when the exchange is resent (e.g. after an attempt to authenticate with no credentials).
 +
 +
You can of course extend HttpExchange directly, but it's probably best to use Jetty's built-in class <tt>org.eclipse.jetty.client.ContentExchange</tt>.
 +
This class overrides most of the callback methods above to allow easy retrieval of the response status code, response headers and response body.
 +
 +
Most of the times, you want to override <tt>onResponseComplete()</tt> to allow your business logic to read the response information (e.g. response status code or response body) and perform additional operations:
 +
 +
<source lang="java">
 +
ContentExchange exchange = new ContentExchange(true)
 +
{
 +
    protected void onResponseComplete() throws IOException
 +
    {
 +
        int status = getResponseStatus();
 +
        if (status == 200)
 +
            doSomething();
 +
        else
 +
            handleError();
 +
    }
 +
};
 +
</source>
 +
 +
== Synchronous Exchanges ==
 +
While asynchronous exchanges offer the most in term of performances, sometimes it is necessary to perform a synchronous exchange without the hassle of overriding methods to be notified of response completion.
 +
This is possible by using the <tt>HttpExchange.waitForDone()</tt> method:
 +
 +
<source lang="java">
 +
HttpClient client = new HttpClient();
 +
client.start();
 +
 +
ContentExchange exchange = new ContentExchange(true);
 +
exchange.setURL("http://foobar.com/baz");
 +
 +
client.send(exchange);
 +
 +
// Waits until the exchange is terminated
 +
int exchangeState = exchange.waitForDone();
 +
 +
if (exchangeState == HttpExchange.STATUS_COMPLETED)
 +
    doSomething();
 +
else if (exchangeState == HttpExchange.STATUS_EXCEPTED)
 +
    handleError();
 +
else if (exchangeState == HttpExchange.STATUS_EXPIRED)
 +
    handleSlowServer();
 +
</source>
 +
 +
The <tt>waitForDone()</tt> method waits until the exchange state is in a "final" state, which could be that the exchange terminated successfully, or an exception was thrown or it expired.
 
}}
 
}}
 +
 +
==SSL Connections==
 +
In order to configure HttpClient to validate SSL certificates and/or to supply a client certificate to the server, follow the instructions in [[Jetty/Reference/SSL_Connectors| SSL Connectors Reference]] to configure a [http://download.eclipse.org/jetty/stable-7/apidocs/org/eclipse/jetty/http/ssl/SslContextFactory.html SslContextFactory] object and pass it as a parameter to the HttpClient's constructor.

Latest revision as of 11:39, 9 August 2013



Introduction

Warning2.png
Jetty 7 and Jetty 8 are now EOL (End of Life)




THIS IS NOT THE DOCUMENTATION YOU ARE LOOKING FOR!!!!!






All development and stable releases are being performed with Jetty 9 and Jetty 10.






This wiki is now officially out of date and all content has been moved to the Jetty Documentation Hub






Direct Link to updated documentation: http://www.eclipse.org/jetty/documentation/current/http-client-api.html


HttpClient is the Jetty component that allows to make requests and interpret responses to HTTP servers.

This tutorial takes you through the steps necessary to use the HttpClient in the most effective way.

Details

The HttpClient is by its nature asynchronous. This means that the code that sends the request does not wait for the response to arrive before continuing. Instead, the request is sent concurrently to your code, and the response is interpreted also concurrently with your code.

The HttpClient API offers you callbacks to interact with the request-response lifecycle. These callbacks will be called by the HttpClient implementation to allow further actions to be performed during each request-response event.

A request-response unit is called exchange, and represent the exchange of information with the HTTP server.

There are two main classes in the HttpClient API:

  • org.eclipse.jetty.client.HttpClient, which manages the thread pooling, the proxy setting, the authentication settings, the connector type (blocking or non-blocking), the SSL settings and the timeouts. HttpClient manages the configuration that does not depend on a particular exchange.
  • org.eclipse.jetty.client.HttpExchange, which is the base class that you normally have to subclass that represent the exchange with the HTTP server, and manages HTTP method, the request URI, HTTP headers, request content, HTTP response code, HTTP response headers and response content.

HttpClient Setup

Before exchanging requests/responses with the HTTP server, you need to setup the HttpClient and then start it:

HttpClient client = new HttpClient();
client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
client.start();

You can also choose to setup the maximum number of connections per address (connections are pooled up to that maximum number), or to specify the thread pool, or the timeout:

HttpClient client = new HttpClient();
client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
client.setMaxConnectionsPerAddress(200); // max 200 concurrent connections to every address
client.setThreadPool(new QueuedThreadPool(250)); // max 250 threads
client.setTimeout(30000); // 30 seconds timeout; if no server reply, the request expires
client.start();

Remember to configure the HttpClient before starting it, or the settings will not have effect.

Since HttpClient does not have any settings related to a particular address, it can be used to exchange requests/responses with several HTTP servers. You normally need one HttpClient instance for all your needs, even if you plan to connect to multiple HTTP servers.

Asynchronous Exchanges

Once the HttpClient has been setup, exchanges may be initiated by using the HttpClient.send(HttpExchange exchange) method.

The exchange must be configured with two mandatory fields: the address to connect to, and the request URI, or equivalently with an absolute URL:

HttpExchange exchange = new HttpExchange();
 
// Optionally set the HTTP method
exchange.setMethod("POST");
 
exchange.setAddress(new Address("ping.host.com", 80));
exchange.setURI("/ping");
// Or, equivalently, this:
exchange.setURL("http://ping.host.com/ping");
 
client.send(exchange);
 
System.out.println("Exchange sent");

The most important thing to remember is that the send() method returns immediately after dispatching the exchange to a thread pool for execution, so the System.out is executed immediately after the send() method. It may be well true that the System.out is executed well before the exchange is actually executed, as well as it may be well true that the System.out is executed after the exchange is completely executed (when even the request has been received).

Beware of not assuming anything about the status of the exchange just because you called send().

Controlling the Exchange Progress

Because we used the HttpExchange class directly, without subclassing it, we have neither control nor notifications about the status of the exchange. The HttpExchange class exposes the following callback methods to be overridden to be notified of the status of the exchange:

  • onRequestCommitted(), called when the request line and the request headers have been sent to the HTTP server.
  • onRequestComplete(), called when the request content has been sent to the HTTP server.
  • onResponseStatus(Buffer httpVersion, int statusCode, Buffer statusMessage), called when the response line has been processed; the three parameters hold, respectively, the HTTP version string (e.g. "HTTP/1.1"), the response status code (e.g. 200) and the response status message (e.g. "OK").
  • onResponseHeader(Buffer name, Buffer value), called for each response header that has been processed; the parameters hold the name of the header (e.g. "Content-Length") and the value of the header (e.g. "16384").
  • onResponseHeaderComplete(), called when all response headers have been processed.
  • onResponseContent(Buffer content), called multiple times for each chunk of the response content; the parameter holds the chunk of the content that has been received.
  • onResponseComplete(), called when the response content has been completely received.

Additionally four more methods can be overridden to be notified of non-normal conditions:

  • onConnectionFailed(Throwable x), called when it is not possible to connect to the address specified in the exchange; the parameter holds the exception received while trying to connect.
  • onException(Throwable x), called when a connection was possible, but an error happened later; the parameter holds the exception happened.
  • onExpire(), called when the server did not respond before the timeout configured in the HttpClient.
  • onRetry(), called when the exchange is resent (e.g. after an attempt to authenticate with no credentials).

You can of course extend HttpExchange directly, but it's probably best to use Jetty's built-in class org.eclipse.jetty.client.ContentExchange. This class overrides most of the callback methods above to allow easy retrieval of the response status code, response headers and response body.

Most of the times, you want to override onResponseComplete() to allow your business logic to read the response information (e.g. response status code or response body) and perform additional operations:

ContentExchange exchange = new ContentExchange(true)
{
    protected void onResponseComplete() throws IOException
    {
        int status = getResponseStatus();
        if (status == 200)
            doSomething();
        else
            handleError();
    }
};

Synchronous Exchanges

While asynchronous exchanges offer the most in term of performances, sometimes it is necessary to perform a synchronous exchange without the hassle of overriding methods to be notified of response completion. This is possible by using the HttpExchange.waitForDone() method:

HttpClient client = new HttpClient();
client.start();
 
ContentExchange exchange = new ContentExchange(true);
exchange.setURL("http://foobar.com/baz");
 
client.send(exchange);
 
// Waits until the exchange is terminated
int exchangeState = exchange.waitForDone();
 
if (exchangeState == HttpExchange.STATUS_COMPLETED)
    doSomething();
else if (exchangeState == HttpExchange.STATUS_EXCEPTED)
    handleError();
else if (exchangeState == HttpExchange.STATUS_EXPIRED)
    handleSlowServer();

The waitForDone() method waits until the exchange state is in a "final" state, which could be that the exchange terminated successfully, or an exception was thrown or it expired.

SSL Connections

In order to configure HttpClient to validate SSL certificates and/or to supply a client certificate to the server, follow the instructions in SSL Connectors Reference to configure a SslContextFactory object and pass it as a parameter to the HttpClient's constructor.

Copyright © Eclipse Foundation, Inc. All Rights Reserved.