目录:
1. SpringBoot集成HttpClient
2. 封装服务HttpService.java,处理请求参数
3. 封装ResponseHandler<T>,处理返回结果
4. 单元测试
5. 功能调用
6. 常见问题和解决方法
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 ......
本文分享SpringBoot集成和配置HttpClient的方法,并封装HttpService调用请求和ResponseHandler处理返回结果,添加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<T> | RespStr.java RespJsonObj.java RespJsonArr.java RespFile.java | 对HttpResponse进行处理,读取HttpEntity并对返回内容进行转换 |
单元测试 | HttpServiceTest.java | 测试HttpService发送请求和处理返回结果 |
功能调用 | CheckController.java | 增加REST接口/chk/http,发送HTTP请求并返回结果。 |
代码下载:https://github.com/jextop/StarterApi/
一,SpringBoot集成HttpClient
1. 在pom.xml中添加httpclient, httpcore, httpmime依赖。
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.2</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.4</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.5</version>
</dependency>
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();
}
}
二,封装服务HttpService.java,处理请求参数,调用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<String, String> headers, ResponseHandler<T> handler) {
HttpGet httpGet = new HttpGet(url);
fillHeaders(httpGet, headers);
return sendRequest(httpGet, handler);
}
private static void fillHeaders(HttpRequestBase request, Map<String, String> headers) {
for (Map.Entry<String, String> header : headers.entrySet()) {
request.addHeader(header.getKey(), header.getValue());
}
}
}
HttpService中使用RespStr处理HttpResponse,返回字符串。
三,封装ResponseHandler<T>,处理返回结果
ResponseHandler<T>是httpclient包内提供的接口,实现函数handleResponse()处理HTTP返回结果,封装处理逻辑。
package org.apache.http.client;
import java.io.IOException;
import org.apache.http.HttpResponse;
public interface ResponseHandler<T> {
T handleResponse(HttpResponse var1) throws ClientProtocolException, IOException;
}
封装的4个HTTP返回结果处理类,简化逻辑,提高开发效率。
代码文件 | HTTP返回结果类型 |
RespStr.java | 返回字符串 |
RespJsonObj.java | 返回JSONObject |
RespJsonArr.java | 返回JSONArray |
RespFile.java | 返回二进制文件 |
1. RespStr.java:读取HttpResponse返回的内容,格式化为String字符串
- 调用httpResponse.getEntiry()获取返回结果
- 调用ContentType.get()获取内容类型
- 调用ContentType.getCharset()获取编码格式
- 调用EntityUtils.toString()将返回结果格式化为字符串
public class RespStr implements ResponseHandler<String> {
@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<JSONObject> {
@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<JSONArray> {
@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;
}
}
四,单元测试,调用HttpService发送请求和处理返回结果
五,功能调用
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<String, Object>() {{
put("chk", "http");
put("course", courses);
}};
}
3. REST接口调用HttpSevice示例
六,常见问题和解决方法
l HTTP返回结果乱码,设置UTF-8仍然不能解决?
原因:处理HTTP请求返回结果时,出现乱码是因为设置Charset编码格式不正确,通常设置UTF-8可以解决大部分情况,但并不是所有HTTP服务器都一定使用UTF-8格式。
解决:正确的方法是获取内容编码时的格式:
- 调用httpResponse.getEntiry()获取返回结果
- 调用ContentType.get()获取内容类型
- 调用ContentType.getCharset()获取编码格式
- 调用EntityUtils.toString()将返回结果格式化为字符串
public class RespStr implements ResponseHandler<String> {
@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);
}
}
ResponseHandler<T>是httpclient包内提供的接口,实现函数handleResponse()处理HTTP返回结果。