如何使用HttpClient GET携带RequestParam并解析ResponseBody
Apache HttpClient 实现GET请求的正确写法
原有代码问题
- 未拼接
caseNumbers请求参数,直接使用基础路径创建请求 - 创建客户端和请求对象后未实际执行请求逻辑,提前关闭了HttpClient实例
- 无响应处理、结果反序列化逻辑
- 资源释放无兜底逻辑,容易出现连接泄漏
- 配置项存在拼写错误:
${servce.urlBasePath}应为${service.urlBasePath}
完整Service层实现代码
以下代码完全兼容原有接口定义,无需修改Controller、Service接口的方法签名:
import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.utils.URIBuilder; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; @Service public class ReadCaseByCaseNumberServiceImpl implements ReadCaseByCaseNumberService { @Value("${service.urlBasePath}") private String urlBasePath; @Value("${service.getCaseByCaseNumberPath}") private String getCaseByCaseNumberPath; private final ObjectMapper objectMapper; // 构造注入Spring自带的JSON解析工具,无需额外引入依赖 public ReadCaseByCaseNumberServiceImpl(ObjectMapper objectMapper) { this.objectMapper = objectMapper; } @Override public ReadCaseByCaseNumberResponse getReadCaseByCaseNumberResponse(String caseNumbers) throws IOException { // 1. 构建带参数的请求URI,自动处理URL编码,避免特殊字符异常 URI requestUri; try { requestUri = new URIBuilder(urlBasePath + getCaseByCaseNumberPath) .addParameter("caseNumbers", caseNumbers) .build(); } catch (URISyntaxException e) { throw new IOException("请求地址构建失败", e); } // 2. 创建GET请求、设置请求头 HttpGet httpGet = new HttpGet(requestUri); httpGet.setHeader("Key", "替换为实际的Key值"); httpGet.setHeader("Authorization", "Bearer 替换为实际的鉴权token"); httpGet.setHeader("Accept", "application/json"); // 3. 自动释放资源:try-with-resources语法会在请求结束后自动关闭客户端和响应,无需手动调用close() try (CloseableHttpClient httpClient = HttpClients.createDefault(); CloseableHttpResponse response = httpClient.execute(httpGet)) { // 4. 校验响应状态,非2xx状态直接抛出异常携带错误信息 int statusCode = response.getStatusLine().getStatusCode(); if (statusCode < 200 || statusCode >= 300) { String errorContent = EntityUtils.toString(response.getEntity(), "UTF-8"); throw new IOException("HTTP请求失败,状态码:" + statusCode + ",错误信息:" + errorContent); } // 5. 读取响应内容,反序列化为目标对象返回 String responseBody = EntityUtils.toString(response.getEntity(), "UTF-8"); return objectMapper.readValue(responseBody, ReadCaseByCaseNumberResponse.class); } } }
关键实现说明
- 禁止手动拼接URL参数,使用
URIBuilder可以自动处理参数的URL编码,避免中文、特殊字符导致的请求异常 - 不要手动调用
close()方法释放连接,使用try-with-resources语法可以100%避免连接泄漏问题 - 必须先校验HTTP响应状态码再解析响应体,避免请求失败时把错误信息当JSON解析抛出不明确的异常
- 编码固定指定为UTF-8,避免不同环境默认编码不一致导致的响应乱码问题
生产环境优化建议
- 不要每次请求都新建HttpClient实例,建议在配置类中统一构建带连接池、超时时间、重试策略的
CloseableHttpClientBean,全局注入使用,性能可提升数倍 - Spring MVC注解(
@GetMapping、@RequestParam)建议写在Controller实现类方法上,不要写在接口上,避免注解扫描、AOP代理时出现识别异常 - 敏感请求头(鉴权token、API Key)不要硬编码在代码中,建议统一放到配置文件或配置中心读取
内容的提问来源于stack exchange,提问作者jashoa leninski
相关产品推荐
相关产品推荐

