当前位置: 首页 > 工具软件 > Fluent-json > 使用案例 >

Apache下基于HttpClient的流式组件fluent-hc

卫宁
2023-12-01

前言

在使用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>

GET请求

Request.Get("http://somehost/")
        .connectTimeout(1000)
        .socketTimeout(1000)
        .execute().returnContent().asString();
  • connectTimeout()设置连接超时
  • socketTimeout() 设置文本读取超时
  • execut() 执行远程连接的核心方法,就是发起一个HttpRequest并返回一个HttpResponse
  • returnContent() 获取返回请求结果Content,其实也就是流文本

POST请求

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,是不支持还是什么的,还在探究汇中。。。)
  • 请求体body可以使用方法bodyString()按照文本格式传入即可,如:json字符串的文本类型APPLICATION_JSON
  • bodyForm()方法构造表单提交。
  • 根据需要返回不同的文本类型asBytes(),asString(),也支持直接写入文件saveContent()

Executor执行器

验证缓存身份细节并为后续请求重用

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优点:

  1. 链式操作,简单容读
  2. 不必处理连接管理和资源分配
  3. 连接池技术减少资源开销增强性能
 类似资料: