全部博文(322)
分类: 系统运维
2010-11-12 13:23:08
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.
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:
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.
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(""); 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().
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:
Additionally four more methods can be overridden to be notified of non-normal conditions:
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(); } };
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(""); 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.