HTTPCLIENT-1601, HTTPCLIENT-1603: clarifications in tutorial regarding exception handling and request recovery (automatic re-execution)

git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk@1654758 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Oleg Kalnichevski 2015-01-26 10:41:30 +00:00
parent 5f9f55df16
commit 306334fad7

View File

@ -657,14 +657,71 @@ try {
} }
]]></programlisting> ]]></programlisting>
</section> </section>
<section id="protocol_interceptors">
<title>HTTP protocol interceptors</title>
<para>The HTTP protocol interceptor is a routine that implements a specific aspect of the HTTP
protocol. Usually protocol interceptors are expected to act upon one specific header or
a group of related headers of the incoming message, or populate the outgoing message with
one specific header or a group of related headers. Protocol interceptors can also
manipulate content entities enclosed with messages - transparent content compression /
decompression being a good example. Usually this is accomplished by using the
'Decorator' pattern where a wrapper entity class is used to decorate the original
entity. Several protocol interceptors can be combined to form one logical unit.</para>
<para>Protocol interceptors can collaborate by sharing information - such as a processing
state - through the HTTP execution context. Protocol interceptors can use HTTP context
to store a processing state for one request or several consecutive requests.</para>
<para>Usually the order in which interceptors are executed should not matter as long as they
do not depend on a particular state of the execution context. If protocol interceptors
have interdependencies and therefore must be executed in a particular order, they should
be added to the protocol processor in the same sequence as their expected execution
order.</para>
<para>Protocol interceptors must be implemented as thread-safe. Similarly to servlets,
protocol interceptors should not use instance variables unless access to those variables
is synchronized.</para>
<para>This is an example of how local context can be used to persist a processing state
between consecutive requests:</para>
<programlisting><![CDATA[
CloseableHttpClient httpclient = HttpClients.custom()
.addInterceptorLast(new HttpRequestInterceptor() {
public void process(
final HttpRequest request,
final HttpContext context) throws HttpException, IOException {
AtomicInteger count = (AtomicInteger) context.getAttribute("count");
request.addHeader("Count", Integer.toString(count.getAndIncrement()));
}
})
.build();
AtomicInteger count = new AtomicInteger(1);
HttpClientContext localContext = HttpClientContext.create();
localContext.setAttribute("count", count);
HttpGet httpget = new HttpGet("http://localhost/");
for (int i = 0; i < 10; i++) {
CloseableHttpResponse response = httpclient.execute(httpget, localContext);
try {
HttpEntity entity = response.getEntity();
} finally {
response.close();
}
}
]]></programlisting>
</section>
<section> <section>
<title>Exception handling</title> <title>Exception handling</title>
<para>HttpClient can throw two types of exceptions: <para>HTTP protocol processors can throw two types of exceptions:
<exceptionname>java.io.IOException</exceptionname> in case of an I/O failure such as <exceptionname>java.io.IOException</exceptionname> in case of an I/O failure such as
socket timeout or an socket reset and <exceptionname>HttpException</exceptionname> that socket timeout or an socket reset and <exceptionname>HttpException</exceptionname> that
signals an HTTP failure such as a violation of the HTTP protocol. Usually I/O errors are signals an HTTP failure such as a violation of the HTTP protocol. Usually I/O errors are
considered non-fatal and recoverable, whereas HTTP protocol errors are considered fatal considered non-fatal and recoverable, whereas HTTP protocol errors are considered fatal
and cannot be automatically recovered from.</para> and cannot be automatically recovered from. Please note that <interfacename>HttpClient
</interfacename> implementations re-throw <exceptionname>HttpException</exceptionname>s
as <exceptionname>ClientProtocolException</exceptionname>, which is a subclass
of <exceptionname>java.io.IOException</exceptionname>. This enables the users
of <interfacename>HttpClient</interfacename> to handle both I/O errors and protocol
violations from a single catch clause.</para>
<section> <section>
<title>HTTP transport safety</title> <title>HTTP transport safety</title>
<para>It is important to understand that the HTTP protocol is not well suited to all <para>It is important to understand that the HTTP protocol is not well suited to all
@ -699,9 +756,10 @@ try {
<para>Please note that this problem is not specific to HttpClient. Browser based <para>Please note that this problem is not specific to HttpClient. Browser based
applications are subject to exactly the same issues related to HTTP methods applications are subject to exactly the same issues related to HTTP methods
non-idempotency.</para> non-idempotency.</para>
<para>HttpClient assumes non-entity enclosing methods such as <literal>GET</literal> and <para>By default HttpClient assumes only non-entity enclosing methods such as
<literal>HEAD</literal> to be idempotent and entity enclosing methods such as <literal>GET</literal> and <literal>HEAD</literal> to be idempotent and entity
<literal>POST</literal> and <literal>PUT</literal> to be not.</para> enclosing methods such as <literal>POST</literal> and <literal>PUT</literal> to be
not for compatibility reasons.</para>
</section> </section>
<section> <section>
<title>Automatic exception recovery</title> <title>Automatic exception recovery</title>
@ -773,6 +831,11 @@ CloseableHttpClient httpclient = HttpClients.custom()
.setRetryHandler(myRetryHandler) .setRetryHandler(myRetryHandler)
.build(); .build();
]]></programlisting> ]]></programlisting>
<para>Please note that one can use <classname>StandardHttpRequestRetryHandler</classname>
instead of the one used by default in order to treat those request methods defined
as idempotent by RFC-2616 as safe to retry automatically: <literal>GET</literal>,
<literal>HEAD</literal>, <literal>PUT</literal>, <literal>DELETE</literal>, <literal>
OPTIONS</literal>, and <literal>TRACE</literal>.</para>
</section> </section>
</section> </section>
<section> <section>
@ -787,58 +850,6 @@ CloseableHttpClient httpclient = HttpClients.custom()
- even if currently blocked in an I/O operation - is guaranteed to unblock by throwing a - even if currently blocked in an I/O operation - is guaranteed to unblock by throwing a
<exceptionname>InterruptedIOException</exceptionname></para> <exceptionname>InterruptedIOException</exceptionname></para>
</section> </section>
<section id="protocol_interceptors">
<title>HTTP protocol interceptors</title>
<para>The HTTP protocol interceptor is a routine that implements a specific aspect of the HTTP
protocol. Usually protocol interceptors are expected to act upon one specific header or
a group of related headers of the incoming message, or populate the outgoing message with
one specific header or a group of related headers. Protocol interceptors can also
manipulate content entities enclosed with messages - transparent content compression /
decompression being a good example. Usually this is accomplished by using the
'Decorator' pattern where a wrapper entity class is used to decorate the original
entity. Several protocol interceptors can be combined to form one logical unit.</para>
<para>Protocol interceptors can collaborate by sharing information - such as a processing
state - through the HTTP execution context. Protocol interceptors can use HTTP context
to store a processing state for one request or several consecutive requests.</para>
<para>Usually the order in which interceptors are executed should not matter as long as they
do not depend on a particular state of the execution context. If protocol interceptors
have interdependencies and therefore must be executed in a particular order, they should
be added to the protocol processor in the same sequence as their expected execution
order.</para>
<para>Protocol interceptors must be implemented as thread-safe. Similarly to servlets,
protocol interceptors should not use instance variables unless access to those variables
is synchronized.</para>
<para>This is an example of how local context can be used to persist a processing state
between consecutive requests:</para>
<programlisting><![CDATA[
CloseableHttpClient httpclient = HttpClients.custom()
.addInterceptorLast(new HttpRequestInterceptor() {
public void process(
final HttpRequest request,
final HttpContext context) throws HttpException, IOException {
AtomicInteger count = (AtomicInteger) context.getAttribute("count");
request.addHeader("Count", Integer.toString(count.getAndIncrement()));
}
})
.build();
AtomicInteger count = new AtomicInteger(1);
HttpClientContext localContext = HttpClientContext.create();
localContext.setAttribute("count", count);
HttpGet httpget = new HttpGet("http://localhost/");
for (int i = 0; i < 10; i++) {
CloseableHttpResponse response = httpclient.execute(httpget, localContext);
try {
HttpEntity entity = response.getEntity();
} finally {
response.close();
}
}
]]></programlisting>
</section>
<section> <section>
<title>Redirect handling</title> <title>Redirect handling</title>
<para>HttpClient handles all types of redirects automatically, except those explicitly <para>HttpClient handles all types of redirects automatically, except those explicitly