Apache HttpClient4.3 Fluent API使用心得小结
2015-08-01 23:58
411 查看
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);
}
}
}
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);
}
}
}
相关文章推荐
- HTTP长连接和短连接
- Apache HttpComponents(HTTPClient) Fluent API 使用
- Ubuntu14.04.2无法连接无线网络问题解决方案
- http封装
- 确保Web安全的HTTPS
- Android的Http通信加载页面、下载图片 以及doGet、doPost请求服务器
- HTTP错误状态码定位与解决
- TCP协议详解(二)
- 社会友谊和人群移动:基于位置的社交网络中的用户移动(一)
- HttpClient使用详解
- httpclient中文API
- 黑马程序员------网络编程(TCP&UDP)
- 网络流例题总结
- 虚拟机3中网络模式(桥接、nat、Host-only
- OPENWRT网络打印机TCP/IP共享设置教程 以703N为例
- HTTP协议
- LVQ神经网络的分类
- java网络编程基础:UDP
- (3) HTTP
- PNN神经网络预测类别的例子