Apache HttpClient4.3 Fluent API使用心得小结

HttpClient原来的API非常复杂,而且还要记着关闭InputStream,Http4.3终于提供了Fluent API, 代码在后面给出。

Request.Get(url).execute().returnContent().asString();

通过翻代码,可以看到它线程安全,所有请求会使用一个公共的连接池,总共200连接,每个destination最多100个连接。而且内容会立刻全部读出然后关闭inputsream,不需要再用代码去关闭。

如果你想设置自己的连接池,或者设置超时,则需要先设置好httpClient,然后传入。

Executor executor = Executor.newInstance(httpClient);

String resultString = executor.execute(Request.Get(url)).returnContent().asString();

import java.io.FileNotFoundException;

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

import java.net.HttpURLConnection;

import java.net.URL;

import javax.servlet.ServletConfig;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;

import org.apache.commons.lang3.StringUtils;

import org.apache.http.HttpEntity;

import org.apache.http.client.HttpResponseException;

import org.apache.http.client.config.RequestConfig;

import org.apache.http.client.fluent.Executor;

import org.apache.http.client.fluent.Request;

import org.apache.http.client.methods.CloseableHttpResponse;

import org.apache.http.client.methods.HttpGet;

import org.apache.http.impl.client.CloseableHttpClient;

import org.apache.http.impl.client.HttpClientBuilder;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

/**

 * 演示使用多线程安全且带连接池的Apache HttpClient和 JDK两种方案获取远程静态内容并进行展示的Servlet.

 *

 * 另外简单演示了轻量级更易用的Apache HttpClient Fluent API。

 *

 * 演示访问地址如下(contentUrl已经过URL编码):

 * remote-content?contentUrl=http%3A%2F%2Flocalhost%3A8080%2Fshowcase%2Fimages%2Flogo.jpg

 *

 */

public class RemoteContentServlet extends HttpServlet {

private static final long serialVersionUID = -8483811141908827663L;

private static final int TIMEOUT_SECONDS = 20;

private static final int POOL_SIZE = 20;

private static Logger logger = LoggerFactory.getLogger(RemoteContentServlet.class);

private static CloseableHttpClient httpClient;

@Override

public void init(ServletConfig config) throws ServletException {

initApacheHttpClient();

}

@Override

public void destroy() {

destroyApacheHttpClient();

}

@Override

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

// 获取URL

String contentUrl = request.getParameter("contentUrl");

if (StringUtils.isBlank(contentUrl)) {

response.sendError(HttpServletResponse.SC_BAD_REQUEST, "contentUrl parameter is required.");

}

// 基於配置,使用HttpClient或JDK 獲取URL內容

String client = request.getParameter("client");

if ("apache".equals(client)) {

fetchContentByApacheHttpClient(response, contentUrl);

} else {

fetchContentByJDKConnection(response, contentUrl);

}

}

private void fetchContentByApacheHttpClient(HttpServletResponse response, String contentUrl) throws IOException {

// 获取内容

HttpGet httpGet = new HttpGet(contentUrl);

CloseableHttpResponse remoteResponse = httpClient.execute(httpGet);

try {

// 判断返回值

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

if (statusCode >= 400) {

response.sendError(statusCode, "fetch image error from " + contentUrl);

return;

}

HttpEntity entity = remoteResponse.getEntity();

// 设置Header

response.setContentType(entity.getContentType().getValue());

if (entity.getContentLength() > 0) {

response.setContentLength((int) entity.getContentLength());

}

// 输出内容

InputStream input = entity.getContent();

OutputStream output = response.getOutputStream();

// 基于byte数组读取InputStream并直接写入OutputStream, 数组默认大小为4k.

IOUtils.copy(input, output);

output.flush();

} finally {

remoteResponse.close();

}

}

private void fetchContentByJDKConnection(HttpServletResponse response, String contentUrl) throws IOException {

HttpURLConnection connection = (HttpURLConnection) new URL(contentUrl).openConnection();

// 设置Socket超时

connection.setReadTimeout(TIMEOUT_SECONDS * 1000);

try {

connection.connect();

// 真正发出请求

InputStream input;

try {

input = connection.getInputStream();

} catch (FileNotFoundException e) {

response.sendError(HttpServletResponse.SC_NOT_FOUND, contentUrl + " is not found.");

return;

}

// 设置Header

response.setContentType(connection.getContentType());

if (connection.getContentLength() > 0) {

response.setContentLength(connection.getContentLength());

}

// 输出内容

OutputStream output = response.getOutputStream();

try {

// 基于byte数组读取InputStream并直接写入OutputStream, 数组默认大小为4k.

IOUtils.copy(input, output);

output.flush();

} finally {

// 保证InputStream的关闭.

IOUtils.closeQuietly(input);

}

} finally {

connection.disconnect();

}

}

// 创建包含connection pool与超时设置的client

private void initApacheHttpClient() {

RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(TIMEOUT_SECONDS * 1000)

.setConnectTimeout(TIMEOUT_SECONDS * 1000).build();

httpClient = HttpClientBuilder.create().setMaxConnTotal(POOL_SIZE).setMaxConnPerRoute(POOL_SIZE)

.setDefaultRequestConfig(requestConfig).build();

}

private void destroyApacheHttpClient() {

try {

httpClient.close();

} catch (IOException e) {

logger.error("httpclient close fail", e);

}

}

@SuppressWarnings("unused")

public void fluentAPIDemo(String contentUrl) throws IOException {

try {

// demo1: 获取文字 , 使用默认连接池(200 total/100 per route), returnContent()会自动获取全部内容后关闭inputstream。

String resultString = Request.Get(contentUrl).execute().returnContent().asString();

// demo2: 获取图片, 增加超时设定。

byte[] resultBytes = Request.Get(contentUrl).connectTimeout(TIMEOUT_SECONDS * 1000)

.socketTimeout(TIMEOUT_SECONDS * 1000).execute().returnContent().asBytes();

// demo3: 获取图片,使用之前设置好了的自定义连接池与超时的httpClient

Executor executor = Executor.newInstance(httpClient);

String resultString2 = executor.execute(Request.Get(contentUrl)).returnContent().asString();

} catch (HttpResponseException e) {

logger.error("Status code:" + e.getStatusCode(), e);

}

}

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值