HttpClient是Apache Jakarta Common下的子项目,是一个高效的、功能丰富的HTTP客户端编程工具包,以编程的方式通过API传输和接收HTTP消息。主要功能:
l 支持HTTP方法:GET, POST, PUT, DELETE, HEAD, OPTIONS等
l 支持HTTPS协议
l 支持多线程应用和连接管理,可设置最大连接数
l 支持KeepAlive持久连接
l 支持自定义Cookie策略
l 支持代理服务器:ngnix等
l 支持自动跳转
l ......
本文分享Spring集成和配置HttpClient的方法,并封装HttpService,通过添加一个REST接口,演示项目中的实际应用。
代码文件 |
功能要点 |
|
SpringBoot集成HttpClient |
pom.xml |
引入HttpClient依赖:org.apache.httpcomponents包里的httpclient, httpcore, httpmime |
application.yml |
配置HTTP连接属性 |
|
HttpConfig.java |
配置Bean: HttpClient,以及RequestConfig和HttpClientConnectionManager |
|
封装服务HttpService |
HttpService.java |
处理HTTP请求参数,调用HttpClient发送请求 |
处理返回结果ResponseHandler |
RespStr.java RespJsonObj.java RespJsonArr.java RespFile.java |
对HttpResponse进行处理,读取HttpEntity并对返回内容进行转换 |
单元测试 |
HttpServiceTest.java |
测试HttpService发送请求和处理返回结果 |
功能调用 |
CheckController.java |
增加REST接口/chk/http,发送HTTP请求并返回结果。 |
l 代码
Github下载:https://github.com/jextop/StarterApi/
l SpringBoot集成Client
1. 在pom.xml中添加httpclient, httpcore, httpmime依赖。
2. 在application.yml中配置HTTP连接属性,指定最大连接数、超时时间等:
http:
maxTotal: 100
maxPerRoute: 20
socketTimeout: 5000
connectTimeout: 5000
requestTimeout: 5000
3. 在HttpConfig.java中配置Bean,读取HTTP连接属性配置,声明RequestConfig和HttpClientConnectionManager,并且创建HttpClient实例:
@Configuration
@ConfigurationProperties("http")
public class HttpConfig {
private Integer maxTotal;
private Integer maxPerRoute;
private Integer socketTimeout;
private Integer connectTimeout;
private Integer requestTimeout;
@Bean
public HttpClientConnectionManager httpClientConnectionManager() {
PoolingHttpClientConnectionManager connMgr = new PoolingHttpClientConnectionManager();
connMgr.setMaxTotal(maxTotal);
connMgr.setDefaultMaxPerRoute(maxPerRoute);
return connMgr;
}
@Bean
public RequestConfig requestConfig() {
return RequestConfig.custom()
.setSocketTimeout(socketTimeout)
.setConnectTimeout(connectTimeout)
.setConnectionRequestTimeout(requestTimeout)
.build();
}
@Bean
public HttpClient httpClient(HttpClientConnectionManager manager, RequestConfig config) {
return HttpClientBuilder.create()
.setConnectionManager(manager)
.setDefaultRequestConfig(config)
.build();
}
}
l 封装服务HttpService.java,处理HTTP请求参数,调用HttpClient发送请求。
@Service
public class HttpService {
@Autowired
private HttpClient httpClient;
public <T> T sendRequest(HttpRequestBase httpRequest, ResponseHandler<T> handler) {
try {
return httpClient.execute(httpRequest, handler);
} catch (ClientProtocolException e) {
LogUtil.error("Error when sendRequest", e.getMessage());
} catch (IOException e) {
LogUtil.error("Error when sendRequest", e.getMessage());
}
return null;
}
public <T> T sendHttpGet(String url, ResponseHandler<T> handler) {
return sendRequest(new HttpGet(url), handler);
}
public String sendHttpGet(String url) {
return sendHttpGet(url, new RespStr());
}
public <T> T sendHttpGet(String url, Map
HttpGet httpGet = new HttpGet(url);
fillHeaders(httpGet, headers);
return sendRequest(httpGet, handler);
}
private static void fillHeaders(HttpRequestBase request, Map
for (Map.Entry
request.addHeader(header.getKey(), header.getValue());
}
}
}
l 处理返回结果,封装ResponseHandler
1. RespStr.java:读取HttpResponse返回的内容,格式化为String字符串
- 调用httpResponse.getEntiry()获取返回结果
- 调用ContentType.get()获取内容类型
- 调用ContentType.getCharset()获取编码格式
- 调用EntityUtils.toString()将返回结果格式化为字符串
public class RespStr implements ResponseHandler
@Override
public String handleResponse(HttpResponse httpResponse) throws ClientProtocolException, IOException {
HttpEntity entity = httpResponse.getEntity();
ContentType contentType = ContentType.getOrDefault(entity);
Charset charset = contentType.getCharset();
return EntityUtils.toString(entity, charset);
}
}
2. RespJsonObj.java:在返回结果为JSON对象时,转换成JSONObject返回
public class RespJsonObj implements ResponseHandler
@Override
public JSONObject handleResponse(HttpResponse resp) throws ClientProtocolException, IOException {
HttpEntity entity = resp.getEntity();
ContentType contentType = ContentType.getOrDefault(entity);
Charset charset = contentType.getCharset();
String jsonStr = EntityUtils.toString(entity, charset);
// parse JSON object
return JsonUtil.parseObj(jsonStr);
}
}
3. RespJsonArr.java:将HTTP请求返回结果转换成JSONArray返回
public class RespJsonArr implements ResponseHandler
@Override
public JSONArray handleResponse(HttpResponse resp) throws ClientProtocolException, IOException {
HttpEntity entity = resp.getEntity();
ContentType contentType = ContentType.getOrDefault(entity);
Charset charset = contentType.getCharset();
String jsonStr = EntityUtils.toString(entity, charset);
// parse JSON array
return JsonUtil.parseArr(jsonStr);
}
}
4. RespFile.java:在HTTP返回二进制文件时,从Entity中读取二进制内容,并可从Header中获取文件名称。
public class RespFile implements ResponseHandler<byte[]> {
private static final String fileNameFlag = "attachment;fileName=";
private byte[] bytes;
private String fileName;
public byte[] getBytes() {
return bytes;
}
public String getFileName() {
return fileName;
}
@Override
public byte[] handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
// Header: Content-Disposition: attachment;fileName=abc.txt
Header header = response.getFirstHeader("Content-Disposition");
String headerValue = header.getValue();
if (headerValue.startsWith(fileNameFlag)) {
fileName = headerValue.substring(fileNameFlag.length(), headerValue.length());
}
HttpEntity entity = response.getEntity();
bytes = EntityUtils.toByteArray(entity);
return bytes;
}
}
l 单元测试,调用HttpService发送请求和处理返回结果
l 功能调用
1. 增加RestController:CheckController.java
2. 增加REST接口/chk/http,发送HTTP请求并返回结果。
@GetMapping(value = "/chk/http", produces = "application/json")
public Object http() {
String strCourse = httpService.sendHttpGet("https://edu.51cto.com/lecturer/13841865.html");
String[] courses = StrUtil.parse(strCourse, "[1-9]\\d*人学习");
return new HashMap
put("chk", "http");
put("course", courses);
}};
}
l REST接口调用HttpSevice示例