目錄:
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返回結果。