Updated HttpClient tutorial with 4.2 API changes
git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk@1240534 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
10f6da691e
commit
2737e5f066
|
@ -113,7 +113,7 @@ pwd
|
|||
</listitem>
|
||||
<listitem>
|
||||
<formalpara>
|
||||
<title>SPNEGO/Kerberos:</title>
|
||||
<title>SPNEGO:</title>
|
||||
<para><literal>SPNEGO</literal> (<emphasis>S</emphasis>imple and
|
||||
<emphasis>P</emphasis>rotected <literal>GSSAPI</literal>
|
||||
<emphasis>Nego</emphasis>tiation Mechanism) is a <literal>GSSAPI</literal>
|
||||
|
@ -124,6 +124,12 @@ pwd
|
|||
At present HttpClient only supports the Kerberos sub-mechanism. </para>
|
||||
</formalpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<formalpara>
|
||||
<title>Kerberos:</title>
|
||||
<para>Kerberos authentication implementation. </para>
|
||||
</formalpara>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
<section>
|
||||
|
@ -209,7 +215,13 @@ httpclient.getParams().setParameter(AuthPNames.PROXY_AUTH_PREF, authpref);
|
|||
<listitem>
|
||||
<formalpara>
|
||||
<title>AuthPolicy.SPNEGO:</title>
|
||||
<para>SPNEGO/Kerberos authentication</para>
|
||||
<para>SPNEGO authentication</para>
|
||||
</formalpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<formalpara>
|
||||
<title>AuthPolicy.KERBEROS:</title>
|
||||
<para>Kerberos authentication</para>
|
||||
</formalpara>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
@ -327,12 +339,12 @@ HttpResponse response = httpclient.execute(httpget, localContext);
|
|||
|
||||
AuthState proxyAuthState = (AuthState) localContext.getAttribute(
|
||||
ClientContext.PROXY_AUTH_STATE);
|
||||
System.out.println("Proxy auth scope: " + proxyAuthState.getAuthScope());
|
||||
System.out.println("Proxy auth state: " + proxyAuthState.getState());
|
||||
System.out.println("Proxy auth scheme: " + proxyAuthState.getAuthScheme());
|
||||
System.out.println("Proxy auth credentials: " + proxyAuthState.getCredentials());
|
||||
AuthState targetAuthState = (AuthState) localContext.getAttribute(
|
||||
ClientContext.TARGET_AUTH_STATE);
|
||||
System.out.println("Target auth scope: " + targetAuthState.getAuthScope());
|
||||
System.out.println("Target auth state: " + targetAuthState.getState());
|
||||
System.out.println("Target auth scheme: " + targetAuthState.getAuthScheme());
|
||||
System.out.println("Target auth credentials: " + targetAuthState.getCredentials());
|
||||
]]></programlisting>
|
||||
|
@ -490,7 +502,7 @@ EntityUtils.consume(entity2);
|
|||
supports <literal>SPNEGO</literal> authentication more completely.</para>
|
||||
<para>The Sun JRE provides the supporting classes to do nearly all the Kerberos and
|
||||
<literal>SPNEGO</literal> token handling. This means that a lot of the setup is
|
||||
for the GSS classes. The <classname>NegotiateScheme</classname> is a simple class to
|
||||
for the GSS classes. The <classname>SPNegoScheme</classname> is a simple class to
|
||||
handle marshalling the tokens and reading and writing the correct headers.</para>
|
||||
<para>The best way to start is to grab the <literal>KerberosHttpClient.java</literal>
|
||||
file in examples and try and get it to work. There are a lot of issues that can
|
||||
|
@ -583,40 +595,6 @@ Value: 0x01
|
|||
]]>
|
||||
</programlisting>
|
||||
</section>
|
||||
<section>
|
||||
<title>Customizing <literal>SPNEGO</literal> authentication scheme</title>
|
||||
<para>In order to customize <literal>SPNEGO</literal> support a new instance of
|
||||
the <classname>NegotiateSchemeFactory</classname> class must be created and
|
||||
registered with the authentication scheme registry of HttpClient. </para>
|
||||
<programlisting><![CDATA[
|
||||
DefaultHttpClient httpclient = new DefaultHttpClient();
|
||||
NegotiateSchemeFactory nsf = new NegotiateSchemeFactory();
|
||||
httpclient.getAuthSchemes().register(AuthPolicy.SPNEGO, nsf);
|
||||
]]>
|
||||
</programlisting>
|
||||
<para>There are several options that can be used to customize the behaviour of
|
||||
<classname>NegotiateSchemeFactory</classname>. </para>
|
||||
<section>
|
||||
<title>Strip port</title>
|
||||
<para>Strips the port off service names e.g.
|
||||
<literal>HTTP/webserver.ad.example.net:8080</literal> ->
|
||||
<literal>HTTP/webserver.ad.example.net</literal></para>
|
||||
<para>Found it useful when authenticating against JBoss Negotiation.</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Custom <literal>SPNEGO</literal> token generator</title>
|
||||
<para>Use this method to inject a custom
|
||||
<interfacename>SpnegoTokenGenerator</interfacename> class to do the Kerberos
|
||||
to <literal>SPNEGO</literal> token wrapping.
|
||||
The <classname>BouncySpnegoTokenGenerator</classname> implementation is provided
|
||||
as an unsupported contribution from the contrib package. This requires the
|
||||
BouncyCastle libraries <ulink url="http://www.bouncycastle.org/java.html"
|
||||
>"http://www.bouncycastle.org/java.html"</ulink>. Found especially useful
|
||||
when using Java 1.5, which is known to provide only a limited support for
|
||||
<literal>SPNEGO</literal> authentication.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
</chapter>
|
||||
|
|
|
@ -270,37 +270,14 @@ sf.connectSocket(socket, address, null, params);
|
|||
<interfacename>javax.net.ssl.SSLContext</interfacename> as a parameter and use
|
||||
it to create custom configured SSL connections.</para>
|
||||
<programlisting><![CDATA[
|
||||
TrustManager easyTrustManager = new X509TrustManager() {
|
||||
|
||||
@Override
|
||||
public void checkClientTrusted(
|
||||
X509Certificate[] chain,
|
||||
String authType) throws CertificateException {
|
||||
// Oh, I am easy!
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(
|
||||
X509Certificate[] chain,
|
||||
String authType) throws CertificateException {
|
||||
// Oh, I am easy!
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return null;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
HttpParams params = new BasicHttpParams();
|
||||
SSLContext sslcontext = SSLContext.getInstance("TLS");
|
||||
sslcontext.init(null, new TrustManager[] { easyTrustManager }, null);
|
||||
sslcontext.init(null, null, null);
|
||||
|
||||
SSLSocketFactory sf = new SSLSocketFactory(sslcontext);
|
||||
SSLSocket socket = (SSLSocket) sf.createSocket();
|
||||
SSLSocket socket = (SSLSocket) sf.createSocket(params);
|
||||
socket.setEnabledCipherSuites(new String[] { "SSL_RSA_WITH_RC4_128_MD5" });
|
||||
|
||||
HttpParams params = new BasicHttpParams();
|
||||
params.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 1000L);
|
||||
InetSocketAddress address = new InetSocketAddress("locahost", 443);
|
||||
sf.connectSocket(socket, address, null, params);
|
||||
|
@ -485,7 +462,7 @@ httpclient.setRoutePlanner(new HttpRoutePlanner() {
|
|||
Scheme http = new Scheme("http", 80, PlainSocketFactory.getSocketFactory());
|
||||
SchemeRegistry sr = new SchemeRegistry();
|
||||
sr.register(http);
|
||||
ClientConnectionManager connMrg = new SingleClientConnManager(sr);
|
||||
ClientConnectionManager connMrg = new BasicClientConnectionManager(sr);
|
||||
|
||||
// Request new connection. This can be a long process
|
||||
ClientConnectionRequest connRequest = connMrg.requestConnection(
|
||||
|
@ -539,27 +516,27 @@ try {
|
|||
</section>
|
||||
<section>
|
||||
<title>Simple connection manager</title>
|
||||
<para><classname>SingleClientConnManager</classname> is a simple connection manager that
|
||||
maintains only one connection at a time. Even though this class is thread-safe it
|
||||
ought to be used by one execution thread only.
|
||||
<classname>SingleClientConnManager</classname> will make an effort to reuse the
|
||||
connection for subsequent requests with the same route. It will, however, close the
|
||||
existing connection and re-open it for the given route, if the route of the persistent
|
||||
connection does not match that of the connection request. If the connection has been
|
||||
already been allocated, then
|
||||
<exceptionname>java.lang.IllegalStateException</exceptionname> is thrown.</para>
|
||||
<para><classname>SingleClientConnManager</classname> is used by HttpClient per
|
||||
<para><classname>BasicClientConnectionManager</classname> is a simple connection manager
|
||||
that maintains only one connection at a time. Even though this class is thread-safe
|
||||
it ought to be used by one execution thread only.
|
||||
<classname>BasicClientConnectionManager</classname> will make an effort to reuse
|
||||
the connection for subsequent requests with the same route. It will, however, close
|
||||
the existing connection and re-open it for the given route, if the route of the
|
||||
persistent connection does not match that of the connection request.
|
||||
If the connection has been already been allocated, then <exceptionname>
|
||||
java.lang.IllegalStateException</exceptionname> is thrown.</para>
|
||||
<para><classname>BasicClientConnectionManager</classname> is used by HttpClient per
|
||||
default.</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Pooling connection manager</title>
|
||||
<para><classname>ThreadSafeClientConnManager</classname> is a more complex
|
||||
<para><classname>PoolingClientConnectionManager</classname> is a more complex
|
||||
implementation that manages a pool of client connections and is able to service
|
||||
connection requests from multiple execution threads. Connections are pooled on a per
|
||||
route basis. A request for a route for which the manager already has a persistent
|
||||
connection available in the pool will be serviced by leasing a connection from
|
||||
the pool rather than creating a brand new connection.</para>
|
||||
<para><classname>ThreadSafeClientConnManager</classname> maintains a maximum limit of
|
||||
<para><classname>PoolingClientConnectionManager</classname> maintains a maximum limit of
|
||||
connections on a per route basis and in total. Per default this implementation will
|
||||
create no more than 2 concurrent connections per given route and no more 20
|
||||
connections in total. For many real-world applications these limits may prove too
|
||||
|
@ -573,14 +550,14 @@ schemeRegistry.register(
|
|||
schemeRegistry.register(
|
||||
new Scheme("https", 443, SSLSocketFactory.getSocketFactory()));
|
||||
|
||||
ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(schemeRegistry);
|
||||
PoolingClientConnectionManager cm = new PoolingClientConnectionManager(schemeRegistry);
|
||||
// Increase max total connection to 200
|
||||
cm.setMaxTotalConnections(200);
|
||||
cm.setMaxTotal(200);
|
||||
// Increase default max connection per route to 20
|
||||
cm.setDefaultMaxPerRoute(20);
|
||||
// Increase max connections for localhost:80 to 50
|
||||
HttpHost localhost = new HttpHost("locahost", 80);
|
||||
cm.setMaxForRoute(new HttpRoute(localhost), 50);
|
||||
cm.setMaxPerRoute(new HttpRoute(localhost), 50);
|
||||
|
||||
HttpClient httpClient = new DefaultHttpClient(cm);
|
||||
]]></programlisting>
|
||||
|
@ -604,22 +581,23 @@ httpclient.getConnectionManager().shutdown();
|
|||
</section>
|
||||
<section>
|
||||
<title>Multithreaded request execution</title>
|
||||
<para>When equipped with a pooling connection manager such as ThreadSafeClientConnManager,
|
||||
HttpClient can be used to execute multiple requests simultaneously using multiple
|
||||
threads of execution.</para>
|
||||
<para>The <classname>ThreadSafeClientConnManager</classname> will allocate connections based on
|
||||
its configuration. If all connections for a given route have already been leased, a
|
||||
request for a connection will block until a connection is released back to the pool. One
|
||||
can ensure the connection manager does not block indefinitely in the connection request
|
||||
operation by setting <literal>'http.conn-manager.timeout'</literal> to a positive value.
|
||||
If the connection request cannot be serviced within the given time period
|
||||
<exceptionname>ConnectionPoolTimeoutException</exceptionname> will be thrown.</para>
|
||||
<para>When equipped with a pooling connection manager such as <classname>
|
||||
PoolingClientConnectionManager</classname>, HttpClient can be used to execute multiple
|
||||
requests simultaneously using multiple threads of execution.</para>
|
||||
<para>The <classname>PoolingClientConnectionManager</classname> will allocate connections
|
||||
based on its configuration. If all connections for a given route have already been
|
||||
leased, a request for a connection will block until a connection is released back to
|
||||
the pool. One can ensure the connection manager does not block indefinitely in the
|
||||
connection request operation by setting <literal>'http.conn-manager.timeout'</literal>
|
||||
to a positive value. If the connection request cannot be serviced within the given time
|
||||
period <exceptionname>ConnectionPoolTimeoutException</exceptionname> will be thrown.
|
||||
</para>
|
||||
<programlisting><![CDATA[
|
||||
SchemeRegistry schemeRegistry = new SchemeRegistry();
|
||||
schemeRegistry.register(
|
||||
new Scheme("http", 80, PlainSocketFactory.getSocketFactory()));
|
||||
|
||||
ClientConnectionManager cm = new ThreadSafeClientConnManager(schemeRegistry);
|
||||
ClientConnectionManager cm = new PoolingClientConnectionManager(schemeRegistry);
|
||||
HttpClient httpClient = new DefaultHttpClient(cm);
|
||||
|
||||
// URIs to perform GETs on
|
||||
|
|
|
@ -0,0 +1,169 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE preface PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
|
||||
<!--
|
||||
====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
====================================================================
|
||||
|
||||
-->
|
||||
<chapter id="fluent">
|
||||
<title>Fluent API</title>
|
||||
<section>
|
||||
<title>Easy to use facade API</title>
|
||||
<para>
|
||||
As of version of 4.2 HttpClient comes with an easy to use facade API based on the concept
|
||||
of a fluent interface. Fluent facade API exposes only the most fundamental functions of
|
||||
HttpClient and is intended for simple use cases that do not require the full flexibility of
|
||||
HttpClient. For instance, fluent facade API relieves the users from having to deal with
|
||||
connection management and resource deallocation.
|
||||
</para>
|
||||
<para>Here are several examples of HTTP requests executed through the HC fluent API</para>
|
||||
<programlisting><![CDATA[
|
||||
// Execute a GET with timeout settings and return response content as String.
|
||||
Request.Get("http://somehost/")
|
||||
.connectTimeout(1000)
|
||||
.socketTimeout(1000)
|
||||
.execute().returnContent().asString();
|
||||
]]>
|
||||
</programlisting>
|
||||
<programlisting><![CDATA[
|
||||
// Execute a POST with the 'expect-continue' handshake, using HTTP/1.1,
|
||||
// containing a request body as String and return response content as byte array.
|
||||
Request.Post("http://somehost/do-stuff")
|
||||
.useExpectContinue()
|
||||
.version(HttpVersion.HTTP_1_1)
|
||||
.bodyString("Important stuff", ContentType.DEFAULT_TEXT)
|
||||
.execute().returnContent().asBytes();
|
||||
]]>
|
||||
</programlisting>
|
||||
<programlisting><![CDATA[
|
||||
// Execute a POST with a custom header through the proxy containing a request body
|
||||
// as an HTML form and save the result to the file
|
||||
Request.Post("http://somehost/some-form")
|
||||
.addHeader("X-Custom-header", "stuff")
|
||||
.viaProxy(new HttpHost("myproxy", 8080))
|
||||
.bodyForm(Form.form().add("username", "vip").add("password", "secret").build())
|
||||
.execute().saveContent(new File("result.dump"));
|
||||
]]>
|
||||
</programlisting>
|
||||
<para>One can also use <classname>Executor</classname> directly in order to execute requests in
|
||||
a specific security context whereby authentication details are cached and re-used for
|
||||
subsequent requests.
|
||||
</para>
|
||||
<programlisting><![CDATA[
|
||||
Executor executor = Executor.newInstance()
|
||||
.auth(new HttpHost("somehost"), "username", "password")
|
||||
.auth(new HttpHost("myproxy", 8080), "username", "password")
|
||||
.authPreemptive(new HttpHost("myproxy", 8080));
|
||||
|
||||
executor.execute(Request.Get("http://somehost/"))
|
||||
.returnContent().asString();
|
||||
|
||||
executor.execute(Request.Post("http://somehost/do-stuff")
|
||||
.useExpectContinue()
|
||||
.bodyString("Important stuff", ContentType.DEFAULT_TEXT))
|
||||
.returnContent().asString();
|
||||
]]>
|
||||
</programlisting>
|
||||
<section>
|
||||
<title>Response handling</title>
|
||||
<para>The fluent facade API generally relieves the users from having to deal with
|
||||
connection management and resource deallocation. In most cases, though, this comes at
|
||||
a price of having to buffer content of response messages in memory. It is highly
|
||||
recommended to use <interfacename>ResponseHandler</interfacename> for HTTP response
|
||||
processing in order to avoid having to buffer content in memory.</para>
|
||||
<programlisting><![CDATA[
|
||||
Document result = Request.Get("http://somehost/content")
|
||||
.execute().handleResponse(new ResponseHandler<Document>() {
|
||||
|
||||
public Document handleResponse(final HttpResponse response) throws IOException {
|
||||
StatusLine statusLine = response.getStatusLine();
|
||||
HttpEntity entity = response.getEntity();
|
||||
if (statusLine.getStatusCode() >= 300) {
|
||||
throw new HttpResponseException(
|
||||
statusLine.getStatusCode(),
|
||||
statusLine.getReasonPhrase());
|
||||
}
|
||||
if (entity == null) {
|
||||
throw new ClientProtocolException("Response contains no content");
|
||||
}
|
||||
DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
|
||||
try {
|
||||
DocumentBuilder docBuilder = dbfac.newDocumentBuilder();
|
||||
ContentType contentType = ContentType.getOrDefault(entity);
|
||||
if (!contentType.equals(ContentType.APPLICATION_XML)) {
|
||||
throw new ClientProtocolException("Unexpected content type:" + contentType);
|
||||
}
|
||||
String charset = contentType.getCharset();
|
||||
if (charset == null) {
|
||||
charset = HTTP.DEFAULT_CONTENT_CHARSET;
|
||||
}
|
||||
return docBuilder.parse(entity.getContent(), charset);
|
||||
} catch (ParserConfigurationException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
} catch (SAXException ex) {
|
||||
throw new ClientProtocolException("Malformed XML document", ex);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
]]>
|
||||
</programlisting>
|
||||
</section>
|
||||
<section>
|
||||
<title>Asynchronous execution</title>
|
||||
<para>The fluent facade API can be used to execute multiple requests asynchronously using
|
||||
background threads.
|
||||
</para>
|
||||
<programlisting><![CDATA[
|
||||
ExecutorService threadpool = Executors.newFixedThreadPool(2);
|
||||
Async async = Async.newInstance().use(threadpool);
|
||||
|
||||
Request[] requests = new Request[] {
|
||||
Request.Get("http://www.google.com/"),
|
||||
Request.Get("http://www.yahoo.com/"),
|
||||
Request.Get("http://www.apache.com/"),
|
||||
Request.Get("http://www.apple.com/")
|
||||
};
|
||||
|
||||
Queue<Future<Content>> queue = new LinkedList<Future<Content>>();
|
||||
for (final Request request: requests) {
|
||||
Future<Content> future = async.execute(request, new FutureCallback<Content>() {
|
||||
|
||||
public void failed(final Exception ex) {
|
||||
System.out.println(ex.getMessage() + ": " + request);
|
||||
}
|
||||
|
||||
public void completed(final Content content) {
|
||||
System.out.println("Request completed: " + request);
|
||||
}
|
||||
|
||||
public void cancelled() {
|
||||
}
|
||||
|
||||
});
|
||||
queue.add(future);
|
||||
}
|
||||
|
||||
// Process the queue
|
||||
]]>
|
||||
</programlisting>
|
||||
</section>
|
||||
</section>
|
||||
</chapter>
|
|
@ -40,9 +40,10 @@ HttpResponse response = httpclient.execute(httpget);
|
|||
HttpEntity entity = response.getEntity();
|
||||
if (entity != null) {
|
||||
InputStream instream = entity.getContent();
|
||||
int l;
|
||||
byte[] tmp = new byte[2048];
|
||||
while ((l = instream.read(tmp)) != -1) {
|
||||
try {
|
||||
// do something useful
|
||||
} finally {
|
||||
instream.close();
|
||||
}
|
||||
}
|
||||
]]></programlisting>
|
||||
|
@ -65,28 +66,16 @@ if (entity != null) {
|
|||
HttpGet httpget = new HttpGet(
|
||||
"http://www.google.com/search?hl=en&q=httpclient&btnG=Google+Search&aq=f&oq=");
|
||||
]]></programlisting>
|
||||
<para>HttpClient provides a number of utility methods to simplify creation and
|
||||
modification of request URIs.</para>
|
||||
<para>URI can be assembled programmatically:</para>
|
||||
<para>HttpClient provides <classname>URIBuilder</classname> utility class to simplify
|
||||
creation and modification of request URIs.</para>
|
||||
<programlisting><![CDATA[
|
||||
URI uri = URIUtils.createURI("http", "www.google.com", -1, "/search",
|
||||
"q=httpclient&btnG=Google+Search&aq=f&oq=", null);
|
||||
HttpGet httpget = new HttpGet(uri);
|
||||
System.out.println(httpget.getURI());
|
||||
]]></programlisting>
|
||||
<para>stdout ></para>
|
||||
<programlisting><![CDATA[
|
||||
http://www.google.com/search?q=httpclient&btnG=Google+Search&aq=f&oq=
|
||||
]]></programlisting>
|
||||
<para>Query string can also be generated from individual parameters:</para>
|
||||
<programlisting><![CDATA[
|
||||
List<NameValuePair> qparams = new ArrayList<NameValuePair>();
|
||||
qparams.add(new BasicNameValuePair("q", "httpclient"));
|
||||
qparams.add(new BasicNameValuePair("btnG", "Google Search"));
|
||||
qparams.add(new BasicNameValuePair("aq", "f"));
|
||||
qparams.add(new BasicNameValuePair("oq", null));
|
||||
URI uri = URIUtils.createURI("http", "www.google.com", -1, "/search",
|
||||
URLEncodedUtils.format(qparams, "UTF-8"), null);
|
||||
URIBuilder builder = new URIBuilder();
|
||||
builder.setScheme("http").setHost("www.google.com").setPath("/search")
|
||||
.setParameter("q", "httpclient")
|
||||
.setParameter("btnG", "Google Search")
|
||||
.setParameter("aq", "f")
|
||||
.setParameter("oq", "");
|
||||
URI uri = builder.build();
|
||||
HttpGet httpget = new HttpGet(uri);
|
||||
System.out.println(httpget.getURI());
|
||||
]]></programlisting>
|
||||
|
@ -276,19 +265,16 @@ domain=localhost
|
|||
supplied by the creator of the entity.</para>
|
||||
<programlisting><![CDATA[
|
||||
StringEntity myEntity = new StringEntity("important message",
|
||||
"UTF-8");
|
||||
ContentType.create("text/plain", "UTF-8"));
|
||||
|
||||
System.out.println(myEntity.getContentType());
|
||||
System.out.println(myEntity.getContentLength());
|
||||
System.out.println(EntityUtils.getContentCharSet(myEntity));
|
||||
System.out.println(EntityUtils.toString(myEntity));
|
||||
System.out.println(EntityUtils.toByteArray(myEntity).length);
|
||||
]]></programlisting>
|
||||
System.out.println(EntityUtils.toByteArray(myEntity).length);]]></programlisting>
|
||||
<para>stdout ></para>
|
||||
<programlisting><![CDATA[
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Type: text/plain; charset=utf-8
|
||||
17
|
||||
UTF-8
|
||||
important message
|
||||
17
|
||||
]]></programlisting>
|
||||
|
@ -394,7 +380,7 @@ if (entity != null) {
|
|||
<classname>FileEntity</classname>.</para>
|
||||
<programlisting><![CDATA[
|
||||
File file = new File("somefile.txt");
|
||||
FileEntity entity = new FileEntity(file, "text/plain; charset=\"UTF-8\"");
|
||||
FileEntity entity = new FileEntity(file, ContentType.create("text/plain", "UTF-8"));
|
||||
|
||||
HttpPost httppost = new HttpPost("http://localhost/action.do");
|
||||
httppost.setEntity(entity);
|
||||
|
@ -404,34 +390,6 @@ httppost.setEntity(entity);
|
|||
implement a custom <interfacename>HttpEntity</interfacename> class which is
|
||||
self-contained instead of using the generic <classname>InputStreamEntity</classname>.
|
||||
<classname>FileEntity</classname> can be a good starting point.</para>
|
||||
<section>
|
||||
<title>Dynamic content entities</title>
|
||||
<para>Often HTTP entities need to be generated dynamically based a particular
|
||||
execution context. HttpClient provides support for dynamic entities by using
|
||||
the <classname>EntityTemplate</classname> entity class and
|
||||
<interfacename>ContentProducer</interfacename> interface. Content producers
|
||||
are objects which produce their content on demand, by writing it out to an
|
||||
output stream. They are expected to be able produce their content every time
|
||||
they are requested to do so. So entities created with
|
||||
<classname>EntityTemplate</classname> are generally self-contained and
|
||||
repeatable.</para>
|
||||
<programlisting><![CDATA[
|
||||
ContentProducer cp = new ContentProducer() {
|
||||
public void writeTo(OutputStream outstream) throws IOException {
|
||||
Writer writer = new OutputStreamWriter(outstream, "UTF-8");
|
||||
writer.write("<response>");
|
||||
writer.write(" <content>");
|
||||
writer.write(" important stuff");
|
||||
writer.write(" </content>");
|
||||
writer.write("</response>");
|
||||
writer.flush();
|
||||
}
|
||||
};
|
||||
HttpEntity entity = new EntityTemplate(cp);
|
||||
HttpPost httppost = new HttpPost("http://localhost/handler.do");
|
||||
httppost.setEntity(entity);
|
||||
]]></programlisting>
|
||||
</section>
|
||||
<section>
|
||||
<title>HTML forms</title>
|
||||
<para>Many applications need to simulate the process of submitting an
|
||||
|
@ -659,15 +617,6 @@ Final target: http://www.google.ch
|
|||
target server (i.e. the request has not been fully transmitted to the
|
||||
server).</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>HttpClient will automatically retry those methods that have been fully
|
||||
transmitted to the server, but the server failed to respond with an HTTP
|
||||
status code (the server simply drops the connection without sending anything
|
||||
back). In this case it is assumed that the request has not been processed by
|
||||
the server and the application state has not changed. If this assumption may
|
||||
not hold true for the web server your application is targeting it is highly
|
||||
recommended to provide a custom exception handler.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
<section>
|
||||
|
@ -688,12 +637,20 @@ HttpRequestRetryHandler myRetryHandler = new HttpRequestRetryHandler() {
|
|||
// Do not retry if over max retry count
|
||||
return false;
|
||||
}
|
||||
if (exception instanceof NoHttpResponseException) {
|
||||
// Retry if the server dropped connection on us
|
||||
return true;
|
||||
if (exception instanceof InterruptedIOException) {
|
||||
// Timeout
|
||||
return false;
|
||||
}
|
||||
if (exception instanceof SSLHandshakeException) {
|
||||
// Do not retry on SSL handshake exception
|
||||
if (exception instanceof UnknownHostException) {
|
||||
// Unknown host
|
||||
return false;
|
||||
}
|
||||
if (exception instanceof ConnectException) {
|
||||
// Connection refused
|
||||
return false;
|
||||
}
|
||||
if (exception instanceof SSLException) {
|
||||
// SSL handshake exception
|
||||
return false;
|
||||
}
|
||||
HttpRequest request = (HttpRequest) context.getAttribute(
|
||||
|
|
|
@ -66,6 +66,7 @@
|
|||
<xi:include href="statemgmt.xml"/>
|
||||
<xi:include href="authentication.xml"/>
|
||||
<xi:include href="httpagent.xml"/>
|
||||
<xi:include href="fluent.xml"/>
|
||||
<xi:include href="caching.xml"/>
|
||||
<xi:include href="advanced.xml"/>
|
||||
|
||||
|
|
Loading…
Reference in New Issue