http 服务器传文件给客户端6,HttpClient 4.x 使用详解(基础篇)

1.httpclient获取请求响应的状态码

在发送Http请求之后 - 我们得到一个org.apache.http.HttpResponse的实例- 它允许我们访问响应的状态行,并隐含地显示状态码:

response.getStatusLine().getStatusCode()

使用这个,我们可以验证我们从服务器收到的代码确实是正确的:

@Test

public void givenGetRequestExecuted_whenAnalyzingTheResponse_thenCorrectStatusCode()

throws ClientProtocolException, IOException {

HttpClient client = HttpClientBuilder.create().build();

HttpResponse response = client.execute(new HttpGet(SAMPLE_URL));

int statusCode = response.getStatusLine().getStatusCode();

assertThat(statusCode, equalTo(HttpStatus.SC_OK));

}

请注意,我们通过org.apache.http.HttpStatus使用库中预定义的状态码。

2.配置httpclient超时

2.1通过原始字符串参数配置超时

该HttpClient的自带了大量的配置参数-所有这些都可以在一个通用的,地图状的方式来设置。

有3个超时参数需要配置:

DefaultHttpClient httpClient = new DefaultHttpClient();

int timeout = 5; // seconds

HttpParams httpParams = httpClient.getParams();

httpParams.setParameter(

CoreConnectionPNames.CONNECTION_TIMEOUT, timeout * 1000);

httpParams.setParameter(

CoreConnectionPNames.SO_TIMEOUT, timeout * 1000);

// httpParams.setParameter(

// ClientPNames.CONN_MANAGER_TIMEOUT, new Long(timeout * 1000));

注意:由于此JIRA(4.3.2中的规定),最后一个参数 - 连接管理器超时 - 在使用4.3.0或4.3.1版本时被注释掉了。

2.2通过API配置超时

这些参数中最重要的参数 - 前两个 - 也可以通过更安全的API来设置:

DefaultHttpClient httpClient = new DefaultHttpClient();

int timeout = 5; // seconds

HttpParams httpParams = httpClient.getParams();

HttpConnectionParams.setConnectionTimeout(

httpParams, timeout * 1000); // http.connection.timeout

HttpConnectionParams.setSoTimeout(

httpParams, timeout * 1000); // http.socket.timeout

第三个参数在HttpConnectionParams中没有自定义设置器,它仍然需要通过setParameter方法手动设置。

2.3使用新的4.3配置超时。生成器

4.3中介绍的流畅的构建器API提供了在较高级别设置超时的正确方法:

int timeout = 5;

RequestConfig config = RequestConfig.custom()

.setConnectTimeout(timeout * 1000)

.setConnectionRequestTimeout(timeout * 1000)

.setSocketTimeout(timeout * 1000).build();

CloseableHttpClient client =

HttpClientBuilder.create().setDefaultRequestConfig(config).build();

2.4超时属性说明

现在,我们来解释这些不同类型的超时的含义:

Connection Timeout (http.connection.timeout) -建立与远程主机的连接的时间

Socket Timeout (http.socket.timeout) -的时间等待数据-建立连接之后; 两个数据包之间不活动的最长时间

Connection Manager Timeout (setConnectionRequestTimeout)(http.connection-manager.timeout) -connect Manager获取Connection 超时时间。单位毫秒。这个属性是新加的属性,因为目前版本是可以共享连接池的。

前两个参数 - 连接和套接字超时 - 是最重要的,但为获得连接设置超时在高负载情况下显然非常重要,这就是为什么第三个参数不应该被忽略的原因。

2.5使用HttpClient

配置完成后,客户端不能用于执行HTTP请求:

HttpGet getMethod = new HttpGet("http://host:8080/path");

HttpResponse response = httpClient.execute(getMethod);

System.out.println(

"HTTP Status of response: " + response.getStatusLine().getStatusCode());

使用先前定义的客户端,与主机的连接将在5秒内超时,如果连接已建立但未收到数据,则超时也将增加5秒。

请注意,连接超时将导致org.apache.http.conn.ConnectTimeoutException被抛出,而套接字超时将导致一个java.net.SocketTimeoutException。

2.6硬超时

虽然在建立HTTP连接和不接收数据时设置超时非常有用,但有时我们需要为整个请求设置硬超时。

例如,下载一个潜在的大文件适合这个类别 - 在这种情况下,连接可能会成功建立,数据可能会一直通过,但我们仍然需要确保操作不会超过某个特定时间阈。

HttpClient没有任何允许我们为请求设置总超时的配置; 但它确实为请求提供了异常功能,所以我们可以利用该机制来实现一个简单的超时机制:

HttpGet getMethod = new HttpGet(

"http://localhost:8080/spring-security-rest-template/api/bars/1");

int hardTimeout = 5; // seconds

TimerTask task = new TimerTask() {

@Override

public void run() {

if (getMethod != null) {

getMethod.abort();

}

}

};

new Timer(true).schedule(task, hardTimeout * 1000);

HttpResponse response = httpClient.execute(getMethod);

System.out.println(

"HTTP Status of response: " + response.getStatusLine().getStatusCode());

我们使用java.util.Timer和java.util.TimerTask来设置一个简单的延迟任务,在5秒硬超时后中止HTTP GET请求。

2.7超时和DNS循环 - 需要注意的事项

一些较大的域将使用DNS循环配置是非常常见的 - 基本上将相同的域映射到多个IP地址。由于HttpClient尝试连接到超时域的方式,这就给这个域的超时带来了新的挑战:

HttpClient获取到该域的IP路由列表

它会尝试第一个 - 超时(使用我们配置的超时)

它尝试第二个 - 也超时

等等 …

所以,正如你所看到的那样 - 当我们预期它的整体操作不会超时。取而代之的是,当所有可能的路由超时以及更多的时候 - 它将完全透明地发生在客户端(除非你在DEBUG级别配置了你的日志)。以下是一个可以运行并复制此问题的简单示例:

int timeout = 3;

RequestConfig config = RequestConfig.custom().

setConnectTimeout(timeout * 1000).

setConnectionRequestTimeout(timeout * 1000).

setSocketTimeout(timeout * 1000).build();

CloseableHttpClient client = HttpClientBuilder.create()

.setDefaultRequestConfig(config).build();

HttpGet request = new HttpGet("http://www.google.com:81");

response = client.execute(request);

您将注意到具有DEBUG日志级别的重试逻辑:

DEBUG o.a.h.i.c.HttpClientConnectionOperator - Connecting to www.google.com/173.194.34.212:81

DEBUG o.a.h.i.c.HttpClientConnectionOperator -

Connect to www.google.com/173.194.34.212:81 timed out. Connection will be retried using another IP address

DEBUG o.a.h.i.c.HttpClientConnectionOperator - Connecting to www.google.com/173.194.34.208:81

DEBUG o.a.h.i.c.HttpClientConnectionOperator -

Connect to www.google.com/173.194.34.208:81 timed out. Connection will be retried using another IP address

DEBUG o.a.h.i.c.HttpClientConnectionOperator - Connecting to www.google.com/173.194.34.209:81

DEBUG o.a.h.i.c.HttpClientConnectionOperator -

Connect to www.google.com/173.194.34.209:81 timed out. Connection will be retried using another IP address

//...

3.httpclient4取消/中止请求

3.1中止GET请求

要中止正在进行的请求,客户可以简单地使用:

request.abort();

这将确保客户端不必使用整个请求来释放连接:

@Test

public void whenRequestIsCanceled_thenCorrect()

throws ClientProtocolException, IOException {

HttpClient instance = HttpClients.custom().build();

HttpGet request = new HttpGet(SAMPLE_URL);

HttpResponse response = instance.execute(request);

try {

System.out.println(response.getStatusLine());

request.abort();

} finally {

response.close();

}

}

4.HttpClient 4不遵循重定向

4.1 在HttpClient 4.3之前

在旧版本的Http客户端(4.3版之前)中,我们可以配置客户端重定向的功能,如下所示:

@Test

public void givenRedirectsAreDisabled_whenConsumingUrlWhichRedirects_thenNotRedirected()

throws ClientProtocolException, IOException {

DefaultHttpClient instance = new DefaultHttpClient();

HttpParams params = new BasicHttpParams();

params.setParameter(ClientPNames.HANDLE_REDIRECTS, false);

// HttpClientParams.setRedirecting(params, false); // alternative

HttpGet httpGet = new HttpGet("http://t.co/I5YYd9tddw");

httpGet.setParams(params);

CloseableHttpResponse response = instance.execute(httpGet);

assertThat(response.getStatusLine().getStatusCode(), equalTo(301));

}

注意可以使用替代API来配置重定向行为,而不用设置实际的原始  http.protocol.handle-redirects参数:

HttpClientParams.setRedirecting(params, false);

另外请注意,在禁用了后续重定向的情况下,我们现在可以检查Http Response状态代码是否确实是301永久移动 - 因为它应该是。

4.2在HttpClient 4.3之后

HttpClient 4.3引入了更清洁,更高层次的API来构建和配置客户端:

@Test

public void givenRedirectsAreDisabled_whenConsumingUrlWhichRedirects_thenNotRedirected()

throws ClientProtocolException, IOException {

HttpClient instance = HttpClientBuilder.create().disableRedirectHandling().build();

HttpResponse response = instance.execute(new HttpGet("http://t.co/I5YYd9tddw"));

assertThat(response.getStatusLine().getStatusCode(), equalTo(301));

}

请注意,新的API使用此重定向行为配置整个客户端 - 而不仅仅是个别请求。

5.httpclient4自定义请求头部信息

5.1按要求设置标题 - 在4.3之前

您可以使用简单的setHeader调用在请求上设置任何自定义标题:

HttpClient client = new DefaultHttpClient();

HttpGet request = new HttpGet(SAMPLE_URL);

request.setHeader(HttpHeaders.CONTENT_TYPE, "application/json");

5.2请求标题 - 4.3及以上

HttpClient 4.3引入了一种构建请求的新方法 - RequestBuilder。要设置标题,我们将在构建器上使用相同的setHeader方法:

HttpClient client = HttpClients.custom().build();

HttpUriRequest request = RequestBuilder.get()

.setUri(SAMPLE_URL)

.setHeader(HttpHeaders.CONTENT_TYPE, "application/json")

.build();

client.execute(request);

5.3在客户端设置默认标题 - 4.3及以上

除了在每个请求上设置标题,您还可以将其配置为客户端本身的默认标题:

Header header = new BasicHeader(

HttpHeaders.CONTENT_TYPE, "application/json");

List headers = Lists.newArrayList(header);

HttpClient client = HttpClients.custom()

.setDefaultHeaders(headers).build();

HttpUriRequest request = RequestBuilder.get()

.setUri(SAMPLE_URL).build();

client.execute(request);

当所有请求的头部需要相同时,这非常有用 - 例如自定义应用程序头部。

6.httpclient4.3版本以上常见操作

创建http客户端

CloseableHttpClient client = HttpClientBuilder.create().build();

发送基本的GET请求

instance.execute(new HttpGet("http://www.google.com"));

获取HTTP响应的状态码

CloseableHttpResponse response = instance.execute(new HttpGet("http://www.google.com"));

assertThat(response.getStatusLine().getStatusCode(), equalTo(200));

获取响应的媒体类型

CloseableHttpResponse response = instance.execute(new HttpGet("http://www.google.com"));

assertThat(response.getStatusLine().getStatusCode(), equalTo(200));

获取响应的媒体类型

CloseableHttpResponse response = instance.execute(new HttpGet("http://www.google.com"));

String contentMimeType = ContentType.getOrDefault(response.getEntity()).getMimeType();

assertThat(contentMimeType, equalTo(ContentType.TEXT_HTML.getMimeType()));

得到响应的主体

CloseableHttpResponse response = instance.execute(new HttpGet("http://www.google.com"));

String bodyAsString = EntityUtils.toString(response.getEntity());

assertThat(bodyAsString, notNullValue());

配置请求的超时时间

@Test(expected = SocketTimeoutException.class)

public void givenLowTimeout_whenExecutingRequestWithTimeout_thenException()

throws ClientProtocolException, IOException {

RequestConfig requestConfig = RequestConfig.custom()

.setConnectionRequestTimeout(1000).setConnectTimeout(1000).setSocketTimeout(1000).build();

HttpGet request = new HttpGet(SAMPLE_URL);

request.setConfig(requestConfig);

instance.execute(request);

}

在整个客户端上配置超时

RequestConfig requestConfig = RequestConfig.custom().

setConnectionRequestTimeout(1000).setConnectTimeout(1000).setSocketTimeout(1000).build();

HttpClientBuilder builder = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig);

发送POST请求

instance.execute(new HttpPost(SAMPLE_URL));

将参数添加到请求

List params = new ArrayList();

params.add(new BasicNameValuePair("key1", "value1"));

params.add(new BasicNameValuePair("key2", "value2"));

request.setEntity(new UrlEncodedFormEntity(params, Consts.UTF_8));

配置如何处理HTTP请求的重定向

CloseableHttpClient instance = HttpClientBuilder.create().disableRedirectHandling().build();

CloseableHttpResponse response = instance.execute(new HttpGet("http://t.co/I5YYd9tddw"));

assertThat(response.getStatusLine().getStatusCode(), equalTo(301));

为请求配置标题

HttpGet request = new HttpGet(SAMPLE_URL);

request.addHeader(HttpHeaders.ACCEPT, "application/xml");

response = instance.execute(request);

从响应中获取头文件

CloseableHttpResponse response = instance.execute(new HttpGet(SAMPLE_URL));

Header[] headers = response.getHeaders(HttpHeaders.CONTENT_TYPE);

assertThat(headers, not(emptyArray()));

关闭/释放资源

response = instance.execute(new HttpGet(SAMPLE_URL));

try {

HttpEntity entity = response.getEntity();

if (entity != null) {

InputStream instream = entity.getContent();

instream.close();

}

} finally {

response.close();

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值