当前位置:   article > 正文

使用HttpClient获取Http状态码及连接池的方法

c#httpclient 获取http状态码

一、开始使用httpclient

本文档需要使用的依赖有如下几个:

fcae772a394b384a819976bab523a080.png

<dependency><groupId>org.apache.httpcomponentsgroupId><artifactId>httpclientartifactId><version>4.5.10version>dependency><dependency><groupId>org.apache.httpcomponentsgroupId><artifactId>httpmimeartifactId><version>4.5.10version>dependency><dependency><groupId>org.apache.httpcomponentsgroupId><artifactId>httpcoreartifactId><version>4.4.11version>dependency>

fcae772a394b384a819976bab523a080.png

1、创建HttpClient对象。

创建httpclient对象的方式有两种,

第一种是使用默认配置创建:

CloseableHttpClient client = HttpClients.createDefault();

第二种是使用HttpClients.custom()定制:

HttpClients.custom().setDefaultRequestConfig(RequestConfig);

这其中RequestConfig的设计方式可以学习一下,也即是建造者模式。RequestConfig只有一个默认访问修饰符的构造函,这就意味着我们在使用这个类的时候不能之间构建示例;RequestConfig有很多私有属性,这些属性没有get/set方法,所以,即便是我们拿到了RequestConfig类的实例,也不能去修改其中的属性值。那么RequestConfig是如何构造实例并且为属性赋值的呢?RequestConfig在实例化的时候会利用其公共内部类Builder。使用方式为RequestConfig.custom().setXXX().builder()。调用custom方法返回一个Builder类实例,改类里有设置RequestConfig同名属性的各种方法,设置完毕后调用builder方法构造一个新的RequestConfig实例。从这个过程中可以看出来,RequestConfig对象的属性是不可变的。

有几个参数我们自己必须设置一下:

(1)connectionRequestTimeout:从连接池中获取连接的超时时间,超过该时间未拿到可用连接,会抛出:ConnectionPoolTimeoutException: Timeout waiting for connection from pool

(2)connectTimeout:连接上服务器(握手成功)的时间,超出该时间抛出connect timeout

(3)socketTimeout:服务器返回数据(response)的时间,超过该时间抛出read timeout

以上3个超时相关的参数如果未配置,默认为-1,意味着无限大,就是一直阻塞等待。

2、创建请求方法的实例

创建请求方法的实例并指定请求URL。如果需要发送GET请求,创建HttpGet对象;如果需要发送POST请求,创建HttpPost对象:

HttpGet httpGet = new HttpGet("https://www.baidu.com");

3、组装请求参数

对于get请求,可以直接在构建HttpGet对象的时候在url中加入,也可以使用URIBuilder构建参数,具体可以参考下面的两种方式:

URIBuilder builder = new URIBuilder("http://example.com/");builder.setParameter("var1""value1").setParameter("var2""value2");HttpGet request = new HttpGet(builder.build());

或使用了建造者模式的URIBuilder

URI uri = new URIBuilder()            .setScheme("http")            .setHost("www.example.cn")            .setPath("/search")            .setParameter("var1", "value1")            .build();

对于HttpPost对象而言,可调用setEntity(HttpEntity entity)方法来设置请求参数:

//拼接参数Listparams= new ArrayList();params.add(new BasicNameValuePair("username", "vip"));params.add(new BasicNameValuePair("password", "secret"));httpPost.setEntity(new UrlEncodedFormEntity(params));

其中setEntity的参数种类可以有很多种,比如:

JSONObject params = new JSONObject();params.put("var1", "value1");params.put("var2", "value2");httpPost.setEntity(new StringEntity(params.toJSONString(), "utf-8"));

或者使用mutltipar形式传输参数:InputStream in = httpResponse.getEntity().getContent();

InputStreamBody inputStreamBody = new InputStreamBody(in, "filename");HttpEntity entity = MultipartEntityBuilder.create()            .addPart("image", inputStreamBody)            .addPart("sign", new StringBody("", ContentType.APPLICATION_XML))            .build();

使用MultipartEntityBuilder需要依赖httpmime包。其中的inputStreamBody是从http查询返回中获得的一个图片的输入流。

4、发送请求

调用HttpClient对象的execute(HttpUriRequest request)发送请求,该方法返回一个HttpResponse:

CloseableHttpResponse httpResponse = httpClient.execute(httpPost);

5、获取返回内容

调用HttpResponse的getAllHeaders()、getHeaders(String name)等方法可获取服务器的响应头;调用HttpResponse的getEntity()方法可获取HttpEntity对象,该对象包装了服务器的响应内容。程序可通过该对象获取服务器的响应内容。

// 获取响应状态码int statusCode = httpResponse.getStatusLine().getStatusCode();// 获取返回内容HttpEntity httpEntity = httpResponse.getEntity();String content = EntityUtils.toString(httpEntity);

6、释放连接。

无论执行方法是否成功,都必须释放连接

httpClient.close();

二、http连接池

1、 为什么使用连接池

  1. 降低延迟:如果不采用连接池,每次连接发起Http请求的时候都会重新建立TCP连接(经历3次握手),用完就会关闭连接(4次挥手),如果采用连接池则减少了这部分时间损耗

  2. 支持更大的并发:如果不采用连接池,每次连接都会打开一个端口,在大并发的情况下系统的端口资源很快就会被用完,导致无法建立新的连接

2、 创建连接池

PoolingHttpClientConnectionManager cm = null;LayeredConnectionSocketFactory sslsf = null;try {    sslsf = new SSLConnectionSocketFactory(SSLContext.getDefault());} catch (NoSuchAlgorithmException e) {    e.printStackTrace();}Registry socketFactoryRegistry = RegistryBuilder.create()        .register("https", sslsf)        .register("http", new PlainConnectionSocketFactory())        .build();cm = new PoolingHttpClientConnectionManager(socketFactoryRegistry);cm.setMaxTotal(200);cm.setDefaultMaxPerRoute(20);CloseableHttpClient httpClient = HttpClients.custom()        .setConnectionManager(cm)        .build();

三、注意事项

1、 错误关闭连接

连接池中连接都是在发起请求的时候建立,并且都是长连接。Client.java[附录]中的in.close()作用就是将用完的连接释放,下次请求可以复用,这里特别注意的是,如果不使用in.close()而仅仅使用response.close(),结果就是连接会被关闭,并且不能被复用,这样就失去了采用连接池的意义。连接池释放连接的时候,并不会直接对TCP连接的状态有任何改变,只是维护了两个Set,leased和avaliabled,leased代表被占用的连接集合,avaliabled代表可用的连接的集合,释放连接的时候仅仅是将连接从leased中remove掉了,并把连接放到avaliabled集合中。

2、 未关闭连接

try{HttpClient httpClient = HttpClientBuilder.create().build();    HttpPost request = new HttpPost(httpUrl);    StringEntity params = new StringEntity(new ObjectMapper().writeValueAsString(body), "UTF-8");    request.addHeader("content-type", "application/json");    request.setEntity(params);    httpClient.execute(request); //问题代码} catch (Exception ex) {    logger.error("Http post error. body={}", body, ex);}

上段代码中,httpClient.execute()执行的返回值response没有被close,导致线程一直在等待。可以改用CloseableHttpClient,并保证httpClient.execute()执行的response最终被close掉。而httpClient无需close,可以重复使用。如果使用CloseableHttpResponse,则response的close也不用显示调用。

CloseableHttpClient httpClient = HttpClientBuilder.create().build();HttpPost request = new HttpPost(httpUrl);StringEntity params = new StringEntity(new ObjectMapper().writeValueAsString(body), "UTF-8");request.addHeader("content-type", "application/json");request.setEntity(params);//httpClient.execute(request);try {    CloseableHttpResponse response = httpClient.execute(request);    //response.close()会被自动调用} catch (Exception ex) {    logger.error("Http post execute error. body={}", body, ex);}

四、附录

1、client.java

public class Client {    HttpConnectionManager connManager;    public  T get(String path,Class clazz){        CloseableHttpClient httpClient=connManager.getHttpClient();        HttpGet httpget = new HttpGet(path);        String json=null;        CloseableHttpResponse response=null;        try {            response = httpClient.execute(httpget);            InputStream in=response.getEntity().getContent();            json=IOUtils.toString(in);            in.close();        } catch (UnsupportedOperationException e) {            e.printStackTrace();        } catch (IOException e) {            e.printStackTrace();        }finally {            if(response!=null){                try {                    response.close();                } catch (IOException e) {                    e.printStackTrace();                }            }        }        return JSON.parseObject(json, clazz);    }}

参考:

HttpClient中文网.http://www.httpclient.cn/

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/648511
推荐阅读
相关标签
  

闽ICP备14008679号