企业🤖AI Agent构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
# httpclient5 <div style="font-size:large;font-weight:bold;"><span style="font-size:19px;">第五章 HTTP客户端服务</span></div><div style="font-size:9.5pt;"><h3>5.1 HttpClient门面</h3><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpClient接口代表了最重要的HTTP请求执行的契约。它没有在请求执行处理上强加限制或特殊细节,而在连接管理,状态管理,认证和处理重定向到具体实现上留下了细节。这应该使得很容易使用额外的功能,比如响应内容缓存来装饰接口。</p><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">DefaultHttpClient 是HttpClient接口的默认实现。这个类扮演了很多特殊用户程序或策略接口实现负责处理特定HTTP协议方面,比如重定向到处理认证或做出关于连接 持久化和保持活动的持续时间决定的门面。这使得用户可以选择使用定制,具体程序等来替换某些方面默认实现。</p><blockquote style="background-color:#F9F9FF;"><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">DefaultHttpClient httpclient = new DefaultHttpClient();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">httpclient.setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy() {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">@Override</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">public long getKeepAliveDuration(HttpResponse response,</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpContext context) {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">long keepAlive = super.getKeepAliveDuration(response, context);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">if (keepAlive == -1) {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">// 如果keep-alive值没有由服务器明确设置,那么保持连接持续5秒。</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">keepAlive = 5000;</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">}</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">return keepAlive;</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">}</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">});</div></blockquote><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">DefaultHttpClient 也维护一组协议拦截器,意在处理即将离开的请求和即将到达的响应,而且提供管理那些拦截器的方法。新的协议拦截器可以被引入到协议处理器链中,或在需要时 从中移除。内部的协议拦截器存储在一个简单的java.util.ArrayList中。它们以被加入到list中的自然顺序来执行。</p><blockquote style="background-color:#F9F9FF;"><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">DefaultHttpClient httpclient = new DefaultHttpClient();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">httpclient.removeRequestInterceptorByClass(RequestUserAgent.class);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">httpclient.addRequestInterceptor(new HttpRequestInterceptor() {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">public void process(</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpRequest request, HttpContext context)</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">throws HttpException, IOException {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">request.setHeader(HTTP.USER_AGENT, "My-own-client");</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">}</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">});</div></blockquote><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">DefaultHttpClient 是线程安全的。建议相同的这个类的实例被重用于多个请求的执行。当一个DefaultHttpClient实例不再需要而且要脱离范围时,和它关联的连接 管理器必须调用ClientConnectionManager#shutdown()方法关闭。</p><blockquote style="background-color:#F9F9FF;"><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpClient httpclient = new DefaultHttpClient();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">// 做些有用的事</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">httpclient.getConnectionManager().shutdown();</div></blockquote><h3>5.2 HttpClient参数</h3><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">这些是可以用于定制默认HttpClient实现行为的参数:</div><ul><li>'http.protocol.handle-redirects':定义了重定向是否应该自动处理。这个参数期望得到一个java.lang.Boolean类型的值。如果这个参数没有被设置,HttpClient将会自动处理重定向。</li><li>'http.protocol.reject- relative-redirect':定义了是否相对的重定向应该被拒绝。HTTP规范需要位置值是一个绝对URI。这个参数期望得到一个 java.lang.Boolean类型的值。如果这个参数没有被设置,那么就允许相对重定向。</li><li>'http.protocol.max- redirects':定义了要遵循重定向的最大数量。这个重定向数字的限制意在防止由破碎的服务器端脚本引发的死循环。这个参数期望得到一个 java.lang.Integer类型的值。如果这个参数没有被设置,那么只允许不多余100次重定向。</li><li>'http.protocol.allow- circular-redirects':定义环形重定向(重定向到相同路径)是否被允许。HTTP规范在环形重定向没有足够清晰的允许表述,因此这作为 可选的是可以开启的。这个参数期望得到一个java.lang.Boolean类型的值。如果这个参数没有被设置,那么环形重定向就不允许。</li><li>'http.connection- manager.factory-class-name':定义了默认的ClientConnectionManager实现的类型。这个参数期望得到一 个java.lang.String类型的值。如果这个参数没有被设置,对于每个默认的将使用SingleClientConnManager。</li><li>'http.virtual-host':定义了在头部信息Host中使用的虚拟主机名称,来代替物理主机名称。这个参数期望得到一个HttpHost类型的值。如果这个参数没有被设置,那么将会使用目标主机的名称或IP地址。</li><li>'http.default-headers':定义了每次请求默认发送的头部信息。这个参数期望得到一个包含Header对象的java.util.Collection类型值。</li><li>'http.default-host':定义了默认主机。如果目标主机没有在请求URI(相对URI)中明确指定,那么就使用默认值。这个参数期望得到一个HttpHost类型的值。</li></ul><h3>5.3 自动重定向处理</h3><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpClient处理所有类型的自动重定向,除了那些由HTTP规范明令禁止的,比如需要用户干预的。参考其它(状态码303)POST和PUT请求重定向转换为由HTTP规范需要的GET请求。</p><h3>5.4 HTTP客户端和执行上下文</h3><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">DefaultHttpClient 将HTTP请求视为不变的对象,也从来不会假定在请求执行期间改变。相反,它创建了一个原请求对象私有的可变副本,副本的属性可以基于执行上下文来更新。 因此,如目标主键和请求URI的final类型的请求参数可以在请求执行之后,由检查本地HTTP上下文来决定。</p><blockquote style="background-color:#F9F9FF;"><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">DefaultHttpClient httpclient = new DefaultHttpClient();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpContext localContext = new BasicHttpContext();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpGet httpget = new HttpGet("http://localhost:8080/");</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpResponse response = httpclient.execute(httpget, localContext);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpHost target = (HttpHost) localContext.getAttribute(</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">ExecutionContext.HTTP_TARGET_HOST);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpUriRequest req = (HttpUriRequest) localContext.getAttribute(</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">ExecutionContext.HTTP_REQUEST);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">System.out.println("Target host: " + target);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">System.out.println("Final request URI: " + req.getURI());</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">System.out.println("Final request method: " + req.getMethod());</div></blockquote></div>