【HttpClient】在 SpringBoot 中使用 HttpClient 实现 HTTP 请求

【HttpURLConnection】使用 HttpURLConnection 后台模拟实现 HTTP 请求
【HttpClient】在 SpringBoot 中使用 HttpClient 实现 HTTP 请求
【SpringBoot】使用 OkHttp 完成网络请求

越来越多的 Java 应用程序需要直接通过 HTTP 协议来访问网络资源。虽然在 JDK 的 java.net 包中已经提供了访问 HTTP 协议的基本功能,但是对于大部分应用程序来说,JDK 库本身提供的功能还不够丰富和灵活。

HttpClient 是 Apache Jakarta Common 下的子项目,用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。

HttpClient 官网

新建一个 SpringBoot 工程,引入 httpclient 的 POM 依赖:

  1. <dependency>
  2. <groupId>org.apache.httpcomponents</groupId>
  3. <artifactId>httpclient</artifactId>
  4. <version>4.5.6</version>
  5. </dependency>

总结:

  1. public class HttpClientUtil {
  2. // GET请求
  3. public static String get(String url, JSONObject params) {
  4. CloseableHttpClient httpClient = HttpClientBuilder.create().build();
  5. String sendUrl = url;
  6. // 拼接参数
  7. if (Objects.nonNull(params) && params.size() > 0) {
  8. sendUrl = connectParams(url, params);
  9. }
  10. HttpGet httpGet = new HttpGet(sendUrl);
  11. CloseableHttpResponse response = null;
  12. try {
  13. response = httpClient.execute(httpGet);
  14. HttpEntity httpEntity = response.getEntity();
  15. if (HttpStatus.SC_OK == response.getStatusLine().getStatusCode() && null != httpEntity) {
  16. return EntityUtils.toString(httpEntity);
  17. }
  18. } catch (IOException e) {
  19. e.printStackTrace();
  20. } finally {
  21. try {
  22. close(httpClient, response);
  23. } catch (IOException e) {
  24. e.printStackTrace();
  25. }
  26. }
  27. throw new JeecgBootException("调用GET请求失败!");
  28. }
  29. /**
  30. * @Description: POST 请求
  31. * @Author: zzc
  32. * @Date: 2022-12-16 16:48
  33. * @param url:
  34. * @param params:
  35. * @param requestBody: json 串
  36. * @return: java.lang.String
  37. **/
  38. public static String post(String url, JSONObject params, String requestBody) {
  39. CloseableHttpClient httpClient = HttpClientBuilder.create().build();
  40. String sendUrl = url;
  41. // 1.拼接参数
  42. if (Objects.nonNull(params) && params.size() > 0) {
  43. sendUrl = connectParams(url, params);
  44. }
  45. HttpPost httpPost = new HttpPost(sendUrl);
  46. httpPost.setHeader("Content-Type", "application/json;charset=utf8");
  47. CloseableHttpResponse response = null;
  48. try {
  49. // 2.设置request-body
  50. if (StringUtils.isNotBlank(requestBody)) {
  51. ByteArrayEntity entity = new ByteArrayEntity(requestBody.getBytes(StandardCharsets.UTF_8));
  52. entity.setContentType("application/json");
  53. httpPost.setEntity(entity);
  54. }
  55. response = httpClient.execute(httpPost);
  56. HttpEntity httpEntity = response.getEntity();
  57. if (HttpStatus.SC_OK == response.getStatusLine().getStatusCode() && null != httpEntity) {
  58. return EntityUtils.toString(httpEntity);
  59. }
  60. } catch (UnsupportedEncodingException e) {
  61. e.printStackTrace();
  62. } catch (ClientProtocolException e) {
  63. e.printStackTrace();
  64. } catch (IOException e) {
  65. e.printStackTrace();
  66. } finally {
  67. try {
  68. close(httpClient, response);
  69. } catch (IOException e) {
  70. e.printStackTrace();
  71. }
  72. }
  73. throw new JeecgBootException("调用POST请求失败!");
  74. }
  75. private static String connectParams(String url, JSONObject params) {
  76. StringBuffer buffer = new StringBuffer();
  77. buffer.append(url).append("?");
  78. params.forEach((x, y) -> buffer.append(x).append("=").append(y).append("&"));
  79. buffer.deleteCharAt(buffer.length() - 1);
  80. return buffer.toString();
  81. }
  82. public static void close(CloseableHttpClient httpClient, CloseableHttpResponse httpResponse) throws IOException{
  83. if (null != httpClient) {
  84. httpClient.close();
  85. }
  86. if (null != httpResponse) {
  87. httpResponse.close();
  88. }
  89. }
  90. }

详细使用示例

GET 无参

调用接口:

  1. http://localhost:8080/http/listUsers

没有入参。

HttpClientController#doGetNoParams():GET请求接口不带参数

  1. @RestController
  2. @RequestMapping("/httpClient")
  3. public class HttpClientController {
  4. @Autowired
  5. private HttpClientService httpClientService;
  6. // GET请求接口不带参数
  7. @GetMapping("/doGetNoParams")
  8. public String doGetNoParams() {
  9. return httpClientService.doGetNoParams();
  10. }
  11. }

HttpClientServiceImpl#doGetNoParams():GET 请求接口不带参数

  1. @Slf4j
  2. @Service
  3. public class HttpClientServiceImpl implements HttpClientService {
  4. // GET请求接口不带参数
  5. @Override
  6. public String doGetNoParams() {
  7. String result = HttpClientUtil.doGetNoParams();
  8. log.info("【发送GET请求】返回结果为:{}", result);
  9. if (!StringUtil.isBlank(result)) {
  10. TaskCenterUtil taskCenterUtil = TaskCenterUtil.getTaskCenterUtil();
  11. taskCenterUtil.submitTask(() -> {
  12. log.info("【子线程】开启了一个新线程,当前线程名为:{}", Thread.currentThread().getName());
  13. return null;
  14. });
  15. }
  16. log.info("【主线程】当前线程名为:{}", Thread.currentThread().getName());
  17. return result;
  18. }
  19. }

说明:

  1. 当 HTTP 调用成功后,通过线程池开一个子线程,去异步执行任务;主线程继续向下执行

HttpClientUtil#doGetNoParams():GET请求接口不带参数

  1. @Slf4j
  2. public class HttpClientUtil {
  3. // 服务器ip
  4. public static final String IP = "http://localhost";
  5. // 端口
  6. public static final String PORT = ":8080";
  7. // GET请求接口不带参数
  8. public static final String GET_URL_NO_PARAMS = IP + PORT + "/http/listUsers";
  9. // GET请求接口不带参数
  10. public static String doGetNoParams() {
  11. CloseableHttpClient httpClient = HttpClientBuilder.create().build();
  12. // 创建 GET 请求
  13. HttpGet httpGet = new HttpGet(GET_URL_NO_PARAMS);
  14. httpGet.setHeader("Accept-Encoding", "identity");
  15. log.info("【发送GET请求】请求地址为:{}", GET_URL_NO_PARAMS);
  16. CloseableHttpResponse httpResponse = null;
  17. try {
  18. httpResponse = httpClient.execute(httpGet);
  19. HttpEntity httpEntity = httpResponse.getEntity();
  20. log.info("【发送GET请求】成功,相应状态为:{}", httpResponse.getStatusLine());
  21. if (HttpStatus.SC_OK == httpResponse.getStatusLine().getStatusCode() && null != httpEntity) {
  22. String result = EntityUtils.toString(httpEntity);
  23. log.info("【发送GET请求】成功,响应内容为:{}", result);
  24. return result;
  25. }
  26. } catch (IOException e) {
  27. log.error("【发送GET请求】失败,执行发送请求时,出现IO异常,异常信息为:{}", e);
  28. return null;
  29. } finally {
  30. try {
  31. close(httpClient, httpResponse);
  32. } catch (IOException e) {
  33. log.error("【发送GET请求】失败,关闭流时,出现IO异常,异常信息为:{}", e);
  34. }
  35. }
  36. return null;
  37. }
  38. }

说明:

  1. 通过类 HttpGet 发起 GET 请求。

HttpGet:有 3 个构造方法

  1. public class HttpGet extends HttpRequestBase {
  2. public HttpGet() {
  3. }
  4. public HttpGet(URI uri) {
  5. this.setURI(uri);
  6. }
  7. public HttpGet(String uri) {
  8. this.setURI(URI.create(uri));
  9. }
  10. ...
  11. }

这里使用了 public HttpGet(String uri); 方式来构造 HttpGet 实例。

HttpClientUtil#close():关闭流

  1. // 关闭流
  2. public static void close(CloseableHttpClient httpClient, CloseableHttpResponse httpResponse) throws IOException{
  3. if (null != httpClient) {
  4. httpClient.close();
  5. }
  6. if (null != httpResponse) {
  7. httpResponse.close();
  8. }
  9. }

TaskCenterUtil:线程池工具类

  1. public class TaskCenterUtil {
  2. public static Integer CORE_POOL_SIZE = 10;
  3. public static Integer MAX_NUM_POOL_SIZE = 10;
  4. public static Integer MAX_MESSAGE_SIZE = 100;
  5. public static Long KEEP_ALIVE_TIME = 60L;
  6. private ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_NUM_POOL_SIZE, KEEP_ALIVE_TIME,
  7. TimeUnit.SECONDS, new LinkedBlockingQueue<>(MAX_MESSAGE_SIZE), new ThreadPoolExecutor.CallerRunsPolicy());
  8. private TaskCenterUtil() {
  9. }
  10. private static TaskCenterUtil taskCenterUtil = new TaskCenterUtil();
  11. public static TaskCenterUtil getTaskCenterUtil() {
  12. return taskCenterUtil;
  13. }
  14. // 提交任务
  15. public void submitTask(Callable task) {
  16. poolExecutor.submit(task);
  17. }
  18. }

POSTMAN 调用:
在这里插入图片描述
控制台打印日志:
在这里插入图片描述
GET 有参

方式一:使用 public HttpGet(String uri); 方式来构造 HttpGet 实例。即:使用 url 字符串来拼接参数。

方式二:使用 public HttpGet(URI uri); 方式来构造 HttpGet 实例。

调用接口:

  1. http://localhost:8080/http/getUserById?id=1

入参:

  1. id=1

HttpClientController#doGetParams():GET请求接口带参数

  1. @GetMapping("/doGetParams")
  2. public String doGetParams(String id) {
  3. return httpClientService.doGetParams(id);
  4. }

HttpClientServiceImpl

  1. @Override
  2. public String doGetParams(String id) {
  3. String result = HttpClientUtil.doGetParams(id);
  4. log.info("【发送GET请求】返回结果为:{}", result);
  5. return result;
  6. }

HttpClientUtil#doGetParams():GET请求接口带参数

  1. @Slf4j
  2. public class HttpClientUtil {
  3. // GET请求接口带参数
  4. public static final String GET_URL_PARAMS = IP + PORT + "/http/getUserById";
  5. // 入参名称
  6. public static final String URL_PARAMS_ID = "id";
  7. // http 协议
  8. public static final String SCHEME_HTTP = "http";
  9. // 主机
  10. public static final String LOCAL_HOST = "localhost";
  11. // 请求接口路径
  12. public static final String GET_URL_PARAMS_PATH = "/http/getUserById";
  13. // 端口
  14. public static final Integer LOCAL_PORT = 8080;
  15. // GET请求接口带参数
  16. public static String doGetParams(String id) {
  17. CloseableHttpClient httpClient = HttpClientBuilder.create().build();
  18. // 不同方式获取 HttpGet
  19. // 方式一:
  20. HttpGet httpGet = getStrHttpGet(GET_URL_PARAMS, id);
  21. // 方式二:
  22. //HttpGet httpGet = getUrlHttpGet(id);
  23. // 获取请求头配置信息
  24. RequestConfig requestConfig = HttpClientConfig.getRequestConfig();
  25. httpGet.setConfig(requestConfig);
  26. CloseableHttpResponse response = null;
  27. try {
  28. response = httpClient.execute(httpGet);
  29. HttpEntity httpEntity = response.getEntity();
  30. log.info("【发送GET请求】成功,相应状态为:{}", response.getStatusLine());
  31. if (HttpStatus.SC_OK == response.getStatusLine().getStatusCode() && null != httpEntity) {
  32. String result = EntityUtils.toString(httpEntity);
  33. log.info("【发送GET请求】成功,响应内容为:{}", result);
  34. return result;
  35. }
  36. } catch (IOException e) {
  37. log.error("【发送GET请求】失败,执行发送请求时,出现IO异常,异常信息为:{}", e);
  38. return null;
  39. } finally {
  40. try {
  41. close(httpClient, response);
  42. } catch (IOException e) {
  43. log.error("【发送GET请求】失败,关闭流时,出现IO异常,异常信息为:{}", e);
  44. }
  45. }
  46. return null;
  47. }
  48. }

getStrHttpGet():方式一:url拼接参数

  1. public static HttpGet getStrHttpGet(String url, String id) {
  2. StringBuilder builder = new StringBuilder();
  3. // url 拼接参数 /http/getUserById?id=1
  4. String strUrl = builder.append(url).append("?").append(URL_PARAMS_ID).append("=").append(id).toString();
  5. log.info("【发送GET请求】请求地址为:{}", strUrl);
  6. HttpGet httpGet = new HttpGet(strUrl);
  7. return httpGet;
  8. }

getUrlHttpGet():方式二:URI对象

  1. public static HttpGet getUrlHttpGet(String id) {
  2. // 将参数键值对放入集合中
  3. List<NameValuePair> params = new ArrayList<>();
  4. params.add(new BasicNameValuePair(URL_PARAMS_ID, id));
  5. try {
  6. URI uri = new URIBuilder()
  7. .setScheme(SCHEME_HTTP)
  8. .setHost(LOCAL_HOST)
  9. .setPort(LOCAL_PORT)
  10. .setPath(GET_URL_PARAMS_PATH)
  11. .setParameters(params).build();
  12. return new HttpGet(uri);
  13. } catch (URISyntaxException e) {
  14. log.error("【发送GET请求】构建URI失败,失败信息为:{}", e);
  15. }
  16. return null;
  17. }

说明:

  1. 方式一是使用 public HttpGet(String uri); 方式来构造 HttpGet 实例
  2. 方式二是使用 public HttpGet(URL uri); 方式来构造 HttpGet 实例。即:使用 url 字符串来拼接参数。

POSTMAN 调用:
在这里插入图片描述
POST 无参

调用接口:

  1. http://localhost:8080/http/listUserList

入参:无

HttpClientController#doPostNoParams():POST请求接口不带参数

  1. @PostMapping("/doPostNoParams")
  2. public String doPostNoParams() {
  3. return httpClientService.doPostNoParams();
  4. }

HttpClientServiceImpl#doPostNoParams()

  1. @Override
  2. public String doPostNoParams() {
  3. String result = HttpClientUtil.doPostNoParams();
  4. log.info("【发送POST请求】返回结果为:{}", result);
  5. return result;
  6. }

HttpClientUtil

  1. public class HttpClientUtil {
  2. // POST请求接口不带参数
  3. public static final String POST_URL_NO_PARAMS = IP + PORT + "/http/listUserList";
  4. // POST请求接口带参数
  5. public static final String POST_URL_PARAMS = IP + PORT + "/http/getUserVoById";
  6. // POST请求接口带参数 -- 对象参数
  7. public static final String POST_URL_PARAMS_OBJECT = IP + PORT + "/http/listUsers";
  8. // POST请求接口不带参数
  9. public static String doPostNoParams() {
  10. CloseableHttpClient httpClient = HttpClientBuilder.create().build();
  11. HttpPost httpPost = new HttpPost(POST_URL_NO_PARAMS);
  12. log.info("【发送POST请求】请求地址为:{}", POST_URL_NO_PARAMS);
  13. CloseableHttpResponse response = null;
  14. try {
  15. response = httpClient.execute(httpPost);
  16. HttpEntity httpEntity = response.getEntity();
  17. log.info("【发送POST请求】成功,相应状态为:{}", response.getStatusLine());
  18. if (HttpStatus.SC_OK == response.getStatusLine().getStatusCode() && null != httpEntity) {
  19. String result = EntityUtils.toString(httpEntity);
  20. log.info("【发送POST请求】成功,响应内容为:{}", result);
  21. return result;
  22. }
  23. } catch (IOException e) {
  24. log.error("【发送POST请求】失败,执行发送请求时,出现IO异常,异常信息为:{}", e);
  25. return null;
  26. } finally {
  27. try {
  28. close(httpClient, response);
  29. } catch (IOException e) {
  30. log.error("【发送POST请求】失败,关闭流时,出现IO异常,异常信息为:{}", e);
  31. }
  32. }
  33. return null;
  34. }
  35. }

POST 有参

参数是:普通参数。方式与GET一样即可,直接在 url 后缀上拼接参数
参数是:对象。将参数以请求体 request-body 的方式进行请求
参数是:普通参数+对象。普通参数 直接在 url 后缀上拼接参数;对象 以请求体 request-body 的方式进行请求

普通参数

请求接口:

  1. http://localhost:8080/http/getUserVoById?id=1

对象参数

请求接口:

  1. http://localhost:8080/http/listUsers

入参 UserVo:

  1. {
  2. "id": 1
  3. }

即:这个接口可以随便写

  1. @PostMapping("/listUsers")
  2. public List<UserVo> listUsers(@RequestBody UserVo userVo) {
  3. return httpService.listUsers();
  4. }

HttpClientController#doPostParams():POST请求接口带参数

  1. @PostMapping("/doPostParams")
  2. public String doPostParams(String id) {
  3. return httpClientService.doPostParams(id);
  4. }

HttpClientServiceImpl#doPostParams()

  1. @Override
  2. public String doPostParams(String id) {
  3. String result = HttpClientUtil.doPostParams(id);
  4. log.info("【发送POST请求】返回结果为:{}", result);
  5. return result;
  6. }

HttpClientUtil#doPostParams()

  1. public static String doPostParams(String id) {
  2. CloseableHttpClient httpClient = HttpClientBuilder.create().build();
  3. // 参数是普通参数
  4. HttpPost httpPost = getStrHttpPost(POST_URL_PARAMS, id);
  5. // 参数是对象
  6. //HttpPost httpPost = getObjectHttpPost(id);
  7. // 设置ContentType(注:如果只是传普通参数的话,ContentType不一定非要用application/json)
  8. httpPost.setHeader("Content-Type", "application/json;charset=utf8");
  9. CloseableHttpResponse response = null;
  10. try {
  11. response = httpClient.execute(httpPost);
  12. HttpEntity httpEntity = response.getEntity();
  13. log.info("【发送POST请求】成功,相应状态为:{}", response.getStatusLine());
  14. if (HttpStatus.SC_OK == response.getStatusLine().getStatusCode() && null != httpEntity) {
  15. String result = EntityUtils.toString(httpEntity);
  16. log.info("【发送POST请求】成功,响应内容为:{}", result);
  17. return result;
  18. }
  19. } catch (IOException e) {
  20. log.error("【发送POST请求】失败,执行发送请求时,出现IO异常,异常信息为:{}", e);
  21. return null;
  22. } finally {
  23. try {
  24. close(httpClient, response);
  25. } catch (IOException e) {
  26. log.error("【发送POST请求】失败,关闭流时,出现IO异常,异常信息为:{}", e);
  27. }
  28. }
  29. return null;
  30. }

getStrHttpPost():POST请求有参:普通参数

  1. public static HttpPost getStrHttpPost(String url, String id) {
  2. StringBuilder builder = new StringBuilder();
  3. // url 拼接参数 /http/getUserVoById?id=1
  4. String strUrl = builder.append(url).append("?").append(URL_PARAMS_ID).append("=").append(id).toString();
  5. log.info("【发送POST请求】请求地址为:{}", strUrl);
  6. HttpPost httpPost = new HttpPost(strUrl);
  7. return httpPost;
  8. }

getObjectHttpPost():POST请求有参:对象参数

  1. public static HttpPost getObjectHttpPost(String id) {
  2. HttpPost httpPost = new HttpPost(POST_URL_PARAMS_OBJECT);
  3. log.info("【发送POST请求】请求地址为:{}", POST_URL_PARAMS_OBJECT);
  4. UserVo userVo = new UserVo();
  5. userVo.setId(id);
  6. // 将JAVA对象转换为Json字符串
  7. String jsonString = JSON.toJSONString(userVo);
  8. StringEntity stringEntity = new StringEntity(jsonString, "UTF-8");
  9. // post请求是将参数放在请求体里面传过去的
  10. httpPost.setEntity(stringEntity);
  11. return httpPost;
  12. }

普通参数 + 对象

  1. // params:name=zzc&age=17 marshal:json 串
  2. public static String post(String url, String params, String marshal) {
  3. CloseableHttpClient httpClient = HttpClientBuilder.create().build();
  4. String strUrl = url + "?" + params;
  5. HttpPost httpPost = new HttpPost(strUrl);
  6. httpPost.setHeader("Content-Type", "application/json;charset=utf8");
  7. CloseableHttpResponse response = null;
  8. try {
  9. // 设置 requst-body 参数
  10. ByteArrayEntity entity = new ByteArrayEntity(marshal.getBytes("UTF-8"));
  11. entity.setContentType("application/json");
  12. httpPost.setEntity(entity);
  13. response = httpClient.execute(httpPost);
  14. HttpEntity httpEntity = response.getEntity();
  15. if (HttpStatus.SC_OK == response.getStatusLine().getStatusCode() && null != httpEntity) {
  16. String result = EntityUtils.toString(httpEntity);
  17. return result;
  18. }
  19. } catch (Exception e) {
  20. e.printStackTrace();
  21. } finally {
  22. try {
  23. close(httpClient, response);
  24. } catch (IOException e) {
  25. e.printStackTrace();
  26. }
  27. }
  28. return null;
  29. }

表单提交

  1. public static String post(String url, Map<String, String> params) {
  2. CloseableHttpClient httpClient = HttpClientBuilder.create().build();
  3. HttpPost httpPost = new HttpPost(url);
  4. httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");
  5. // 参数
  6. List<NameValuePair> nameValuePairs = new ArrayList<>();
  7. if (MapUtils.isNotEmpty(params)) {
  8. params.forEach((x, y) -> {
  9. nameValuePairs.add(new BasicNameValuePair(x, y));
  10. });
  11. }
  12. CloseableHttpResponse response = null;
  13. try {
  14. httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
  15. response = httpClient.execute(httpPost);
  16. HttpEntity httpEntity = response.getEntity();
  17. if (HttpStatus.SC_OK == response.getStatusLine().getStatusCode() && null != httpEntity) {
  18. return EntityUtils.toString(httpEntity);
  19. }
  20. } catch (IOException e) {
  21. e.printStackTrace();
  22. } finally {
  23. try {
  24. close(httpClient, response);
  25. } catch (IOException e) {
  26. e.printStackTrace();
  27. }
  28. }
  29. throw new JeecgBootException("调用accessToken API失败");
  30. }

发表评论

表情:
评论列表 (有 0 条评论,67人围观)

还没有评论,来说两句吧...

相关阅读