注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

小葫芦君(汉斯的博客)

博客迁移到新博客:https://blog.ssxingshou.com

 
 
 

日志

 
 
关于我

小小葫芦商城,为您提供高品质的商品,一流的产品,一流的包装服务,一流的物流服务,放心购买

网易考拉推荐

HttpClient4.3 Fluent API  

2014-11-23 20:05:54|  分类: 默认分类 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

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);
		}
	}
}

  评论这张
 
阅读(6252)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017