在使用HttpClient
进行java端调用http请求时候,发现有流式组件fluent-hc
可以直接用,是对HttpClient
的简单封装
<dependency>
<!--fluent-hc是HttpClient基于流式API封装的客户端-->
<groupId>org.apache.httpcomponents</groupId>
<artifactId>fluent-hc</artifactId>
<version>4.5.8</version>
</dependency>
Request.Get("http://somehost/")
.connectTimeout(1000)
.socketTimeout(1000)
.execute().returnContent().asString();
connectTimeout()
设置连接超时socketTimeout()
设置文本读取超时execut()
执行远程连接的核心方法,就是发起一个HttpRequest
并返回一个HttpResponse
returnContent()
获取返回请求结果Content,其实也就是流文本Request.Post("http://somehost/do-stuff")
.useExpectContinue()
.version(HttpVersion.HTTP_1_1)
.bodyString("{\key\":\"value\"}", ContentType.APPLICATION_JSON)
//.bodyForm(Form.form().add("username", "vip").add("password", "secret").build())
.execute().returnContent().asString();
useExpectContinue()
用户tcp握手version()
指定http传输协议版本(没找到2.0,是不支持还是什么的,还在探究汇中。。。)bodyString()
按照文本格式传入即可,如:json字符串的文本类型APPLICATION_JSON
bodyForm()
方法构造表单提交。asBytes()
,asString()
,也支持直接写入文件saveContent()
验证缓存身份细节并为后续请求重用
Executor executor = Executor.newInstance()
.auth(new HttpHost("somehost"), "username", "password")
.auth(new HttpHost("somehost", 8080), "username", "password")
.authPreemptive(new HttpHost("somehost", 8080));
/**
* 基于Basic Auth 认证
*/
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(AuthScope.ANY,
new UsernamePasswordCredentials("username", "password"));
executor.use(credsProvider);
executor.execute(Request.Get("http://somehost/"))
.returnContent().asString();
executor.execute(Request.Post("http://somehost/do-stuff")
.useExpectContinue()
.bodyString("{\key\":\"value\"}", ContentType.APPLICATION_JSON)
.returnContent().asString();
Executor执行器的CLIENT对象是从连接池中获取的HttpClient对象。采用HTTP连接池技术降低了频繁建立HTTP连接的时间开销,减少了TCP连接建立和释放时socket通信服务器端资源的浪费,同时支持更高的并发量。
public class Executor {
static final PoolingHttpClientConnectionManager CONNMGR;
static final HttpClient CLIENT;
private final HttpClient httpclient;
private volatile AuthCache authCache;
private volatile CredentialsProvider credentialsProvider;
private volatile CookieStore cookieStore;
public static Executor newInstance() {
return new Executor(CLIENT);
}
...
Registry<ConnectionSocketFactory> sfr = RegistryBuilder.create().register("http", PlainConnectionSocketFactory.getSocketFactory()).register("https", ssl != null ? ssl : SSLConnectionSocketFactory.getSocketFactory()).build();
CONNMGR = new PoolingHttpClientConnectionManager(sfr);
//将每个路由的默认最大连接数设置为100
CONNMGR.setDefaultMaxPerRoute(100);
//设置最大连接数
CONNMGR.setMaxTotal(200);
CONNMGR.setValidateAfterInactivity(1000);
CLIENT = HttpClientBuilder.create().setConnectionManager(CONNMGR).build();
}
如上所说,execut()
执行后得到一个HttpResponse
对象,可以使用方法handleResponse()
自定义响应处理。
避免必须在内存中缓冲内容,提高效率。*
如下就是解析xml格式的示例,默认的方法returnContent()
的底层实现其实handleResponse()
。
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);
}
}
});
组件fluent-hc
优点: