HttpClient
介绍
HttpClient是Apache Jakarta Common下的一个子项目,它提供了一个高效的、最新的、功能丰富的支持HTTP协议的客户端编程工具包。它支持HTTP协议最新的版本和建议,并实现了Http1.0和Http1.1协议。
HttpClient具有可扩展的面向对象的结构,实现了Http全部的方法,包括GET、POST、PUT、DELETE、HEAD、OPTIONS以及TRACE。它支持HTTPS协议,并允许通过Http代理建立透明的连接,以及利用CONNECT方法建立隧道的https连接。此外,它还支持多种认证方案,如Basic、Digest、NTLMv1、NTLMv2、NTLM2 Session以及SNPNEGO/Kerberos,并允许使用插件式的自定义认证方案。
在项目中,HttpClient的使用场景广泛,如爬虫、多系统之间的接口交互等。在分布式项目中,前端系统需要调用后台的数据并初始化时,可以使用HttpClient进行通信。
在使用HttpClient时,通常需要导入相关的依赖库,并根据具体需求配置HttpClient的行为,如设置连接超时、读取超时等。然后,可以使用HttpClient发送GET、POST等请求,并处理返回的响应。
在SpringBoot后端项目开发时,什么时候需要HttpClient?
调用第三方服务的时候
构造HTTP请求
HttpClient的maven坐标:
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.13</version> </dependency>
其实阿里云oss已经依赖了httpclient,所以无需再引入这个包
HttpClient的核心API:
-
HttpClient(HttpClient对象接口):Http客户端对象类型,使用该类型对象可发起Http请求。
-
HttpClients:可认为是构建器,可创建HttpClient对象。
-
CloseableHttpClient(HttpClient对象实现类):实现类,实现了HttpClient接口。
-
HttpGet(Http请求对象):Get方式请求类型。
-
HttpPost(Http请求对象):Post方式请求类型。
HttpClient发送请求步骤:
-
创建HttpClient对象
-
创建Http请求对象
-
调用HttpClient的execute方法发送请求
GET请求
实现步骤:
-
创建HttpClient对象
-
创建请求对象
-
发送请求,接受响应结果
-
解析结果
-
关闭资源
package com.sky.test;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class HttpClientTest {
/**
* 测试通过httpclient发送GET方式的请求
*/
@Test
public void testGET() throws Exception{
//创建httpclient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
//创建请求对象
HttpGet httpGet = new HttpGet("http://localhost:8080/user/shop/status");
//发送请求,接受响应结果
CloseableHttpResponse response = httpClient.execute(httpGet);
//获取服务端返回的状态码
int statusCode = response.getStatusLine().getStatusCode();
System.out.println("服务端返回的状态码为:" + statusCode);
HttpEntity entity = response.getEntity();
String body = EntityUtils.toString(entity);
System.out.println("服务端返回的数据为:" + body);
//关闭资源
response.close();
httpClient.close();
}
}
在访问http://localhost:8080/user/shop/status请求时,需要提前启动项目。
注意:
- 创建HttpClient对象需要调用HttpClients.createDefault()方法,创建一个CloseableHttpClient对象
- 创建请求对象:HttpGet httpGet = new HttpGet("请求url");
- 利用HttpCliet对象执行execute请求对象,得到响应结果response:CloseableHttpResponse response = httpClient.execute(httpGet);
- 解析响应结果:
int statusCode = response.getStatusLine().getStatusCode();
System.out.println("服务端返回的状态码为:" + statusCode);HttpEntity entity = response.getEntity();
String body = EntityUtils.toString(entity);
System.out.println("服务端返回的数据为:" + body); -
关闭资源:
response.close();
httpClient.close();
Post请求
在HttpClientTest中添加POST方式请求方法,相比GET请求来说,POST请求若携带参数需要封装请求体对象,并将该对象设置在请求对象中。
实现步骤:
-
创建HttpClient对象
-
创建请求对象
-
发送请求,接收响应结果
-
解析响应结果
-
关闭资源
/**
* 测试通过httpclient发送POST方式的请求
*/
@Test
public void testPOST() throws Exception{
// 创建httpclient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
//创建请求对象
HttpPost httpPost = new HttpPost("http://localhost:8080/admin/employee/login");
JSONObject jsonObject = new JSONObject();
jsonObject.put("username","admin");
jsonObject.put("password","123456");
StringEntity entity = new StringEntity(jsonObject.toString());
//指定请求编码方式
entity.setContentEncoding("utf-8");
//数据格式
entity.setContentType("application/json");
httpPost.setEntity(entity);
//发送请求
CloseableHttpResponse response = httpClient.execute(httpPost);
//解析返回结果
int statusCode = response.getStatusLine().getStatusCode();
System.out.println("响应码为:" + statusCode);
HttpEntity entity1 = response.getEntity();
String body = EntityUtils.toString(entity1);
System.out.println("响应数据为:" + body);
//关闭资源
response.close();
httpClient.close();
}
HttpPost请求对象需要利用setEntity方法补充json格式的请求体数据。
1、打包Json数据
JSONObject jsonObject = new JSONObject();
jsonObject.put("username","admin");
jsonObject.put("password","123456");
StringEntity entity = new StringEntity(jsonObject.toString());
2、设置请求编码方式和数据格式
//指定请求编码方式
entity.setContentEncoding("utf-8");
//数据格式
entity.setContentType("application/json");
3、setEntity打包Json数据
httpPost.setEntity(entity);
4、利用HttpClient对象的execute方法发送请求
CloseableHttpResponse response = httpClient.execute(httpPost);
编写HttpClient工具类
/**
* Http工具类
*/
public class HttpClientUtil {
static final int TIMEOUT_MSEC = 5 * 1000;
/**
* 发送GET方式请求
* @param url
* @param paramMap
* @return
*/
public static String doGet(String url,Map<String,String> paramMap){
// 创建Httpclient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
String result = "";
CloseableHttpResponse response = null;
try{
URIBuilder builder = new URIBuilder(url);
if(paramMap != null){
for (String key : paramMap.keySet()) {
builder.addParameter(key,paramMap.get(key));
}
}
URI uri = builder.build();
//创建GET请求
HttpGet httpGet = new HttpGet(uri);
//发送请求
response = httpClient.execute(httpGet);
//判断响应状态
if(response.getStatusLine().getStatusCode() == 200){
result = EntityUtils.toString(response.getEntity(),"UTF-8");
}
}catch (Exception e){
e.printStackTrace();
}finally {
try {
response.close();
httpClient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
/**
* 发送POST方式请求
* @param url
* @param paramMap
* @return
* @throws IOException
*/
public static String doPost(String url, Map<String, String> paramMap) throws IOException {
// 创建Httpclient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
String resultString = "";
try {
// 创建Http Post请求
HttpPost httpPost = new HttpPost(url);
// 创建参数列表
if (paramMap != null) {
List<NameValuePair> paramList = new ArrayList();
for (Map.Entry<String, String> param : paramMap.entrySet()) {
paramList.add(new BasicNameValuePair(param.getKey(), param.getValue()));
}
// 模拟表单
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList);
httpPost.setEntity(entity);
}
httpPost.setConfig(builderRequestConfig());
// 执行http请求
response = httpClient.execute(httpPost);
resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
} catch (Exception e) {
throw e;
} finally {
try {
response.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return resultString;
}
/**
* 发送POST方式请求
* @param url
* @param paramMap
* @return
* @throws IOException
*/
public static String doPost4Json(String url, Map<String, String> paramMap) throws IOException {
// 创建Httpclient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
String resultString = "";
try {
// 创建Http Post请求
HttpPost httpPost = new HttpPost(url);
if (paramMap != null) {
//构造json格式数据
JSONObject jsonObject = new JSONObject();
for (Map.Entry<String, String> param : paramMap.entrySet()) {
jsonObject.put(param.getKey(),param.getValue());
}
StringEntity entity = new StringEntity(jsonObject.toString(),"utf-8");
//设置请求编码
entity.setContentEncoding("utf-8");
//设置数据类型
entity.setContentType("application/json");
httpPost.setEntity(entity);
}
httpPost.setConfig(builderRequestConfig());
// 执行http请求
response = httpClient.execute(httpPost);
resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
} catch (Exception e) {
throw e;
} finally {
try {
response.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return resultString;
}
private static RequestConfig builderRequestConfig() {
return RequestConfig.custom()
.setConnectTimeout(TIMEOUT_MSEC)
.setConnectionRequestTimeout(TIMEOUT_MSEC)
.setSocketTimeout(TIMEOUT_MSEC).build();
}
}
1. doGet(String url, Map<String,String> paramMap)
输入:
url
: 要请求的URL地址。paramMap
: 一个包含请求参数的Map
对象,键和值都是String
类型。
输出:
- 返回一个
String
类型的结果,表示 HTTP 响应的正文内容。
功能:
- 该方法用于构造一个 HTTP GET 请求。它首先创建一个
HttpClient
对象,然后使用URIBuilder
来添加请求参数。如果响应状态码为200,它将响应正文转换为字符串并返回。
2. doPost(String url, Map<String, String> paramMap) throws IOException
输入:
url
: 要请求的URL地址。paramMap
: 一个包含请求参数的Map
对象。
输出:
- 返回一个
String
类型的结果,表示 HTTP 响应的正文内容。
功能:
- 该方法用于构造一个 HTTP POST 请求,请求参数以表单形式发送。它创建一个
HttpPost
对象,并将参数作为UrlEncodedFormEntity
设置到请求中。然后发送请求并返回响应正文。
3. doPost4Json(String url, Map<String, String> paramMap) throws IOException
输入:
url
: 要请求的URL地址。paramMap
: 一个包含请求参数的Map
对象。
输出:
- 返回一个
String
类型的结果,表示 HTTP 响应的正文内容。
功能:
- 该方法用于构造一个 HTTP POST 请求,请求参数以 JSON 格式发送。它创建一个
HttpPost
对象,并将参数构造为 JSON 对象,然后设置到请求的StringEntity
中。请求的Content-Type
被设置为application/json
,然后发送请求并返回响应正文。
4. builderRequestConfig()
输入:
- 无。
输出:
- 返回一个
RequestConfig
对象。
功能:
- 这是一个私有方法,用于构建
RequestConfig
对象,它设置了连接超时、请求超时和套接字超时的默认值。
使用HttpClient工具类
以下是三个示例,展示如何使用 HttpClientUtil
类提供的前三个方法构造 HTTP 请求,并分析响应结果:
示例 1: 使用 doGet
方法发送 GET 请求
假设我们想要从 http://example.com/api/data
获取一些数据,并且有一些查询参数。
import java.util.HashMap;
import java.util.Map;
public class HttpClientUtilExample {
public static void main(String[] args) {
// 准备请求参数
Map<String, String> params = new HashMap<>();
params.put("param1", "value1");
params.put("param2", "value2");
// 发送 GET 请求
String result = HttpClientUtil.doGet("http://example.com/api/data", params);
// 分析响应结果
if (result != null && !result.isEmpty()) {
System.out.println("Response: " + result);
// 这里可以根据需要解析 JSON 或 XML 响应体
} else {
System.out.println("No response received or error occurred.");
}
}
}
示例 2: 使用 doPost
方法发送表单 POST 请求
假设我们想要向 http://example.com/api/login
发送登录请求。
public class HttpClientUtilExample {
public static void main(String[] args) {
// 准备登录参数
Map<String, String> params = new HashMap<>();
params.put("username", "user123");
params.put("password", "pass123");
try {
// 发送 POST 请求
String result = HttpClientUtil.doPost("http://example.com/api/login", params);
// 分析响应结果
if (result != null && !result.isEmpty()) {
System.out.println("Login Response: " + result);
// 根据响应内容判断登录是否成功
} else {
System.out.println("Login failed or error occurred.");
}
} catch (IOException e) {
e.printStackTrace();
System.out.println("An error occurred during the POST request.");
}
}
}
示例 3: 使用 doPost4Json
方法发送 JSON POST 请求
假设我们想要向 http://example.com/api/register
发送注册请求,并且请求体是 JSON 格式。
public class HttpClientUtilExample {
public static void main(String[] args) {
// 准备登录参数
Map<String, String> params = new HashMap<>();
params.put("username", "user123");
params.put("password", "pass123");
try {
// 发送 POST 请求
String result = HttpClientUtil.doPost("http://example.com/api/login", params);
// 分析响应结果
if (result != null && !result.isEmpty()) {
System.out.println("Login Response: " + result);
// 根据响应内容判断登录是否成功
} else {
System.out.println("Login failed or error occurred.");
}
} catch (IOException e) {
e.printStackTrace();
System.out.println("An error occurred during the POST request.");
}
}
}
在每个示例中,我们首先创建了一个包含请求参数的 Map
对象,然后调用相应的方法发送请求。请求完成后,我们检查响应结果是否为 null
或者为空,如果不是,则打印出响应内容。在处理 POST 请求的示例中,我们还捕获了可能发生的 IOException
。
doPost
和 doPost4Json
是 HttpClientUtil
类中定义的两个发送 POST 请求的方法,它们的主要区别在于发送请求体的格式不同:
doPost 方法:
- 请求体格式:
doPost
方法发送的请求体是标准的表单格式(application/x-www-form-urlencoded
)。 - 参数构建:它使用
UrlEncodedFormEntity
来构建请求体,这适用于传统的表单提交,其中键值对被编码为字符串,并用&
符号分隔。 - 适用场景:当后端服务期望接收表单数据时,使用此方法。
doPost4Json 方法:
- 请求体格式:
doPost4Json
方法发送的请求体是 JSON 格式(application/json
)。 - 参数构建:它使用
JSONObject
来构建请求体,然后将 JSON 对象转换为字符串,并设置到StringEntity
中。 - 适用场景:当后端服务期望接收 JSON 格式的请求体时,使用此方法。
代码层面的区别:
doPost
方法中,参数是通过遍历paramMap
并使用BasicNameValuePair
对象添加到paramList
中,然后构建UrlEncodedFormEntity
对象。doPost4Json
方法中,参数是通过遍历paramMap
并使用JSONObject
的put
方法添加到 JSON 对象中,然后构建StringEntity
对象,并设置正确的Content-Encoding
和Content-Type
。
实际使用时的考虑因素:
- 内容类型:客户端需要根据服务器端的期望来设置正确的
Content-Type
。 - 编码:对于 JSON 请求体,需要确保字符编码正确设置为 UTF-8,以避免编码问题。
- API 约定:不同的 API 可能对请求体的格式有不同的要求,选择正确的方法来满足这些要求是非常重要的。
在实际应用中,选择使用 doPost
还是 doPost4Json
取决于你要与之交互的 API 的具体要求。通常,现代的 RESTful API 更倾向于使用 JSON 格式,因为它结构化更好、更易于解析。然而,一些旧的或特定的系统可能仍然使用传统的表单数据格式。
传统的表单格式,通常指的是 application/x-www-form-urlencoded
格式,这是一种用于 HTTP 请求的编码方式,特别是用于表单数据的提交。在 Web 开发中,这是最常见的数据提交方式之一。
特点:
- 键值对:数据由键值对组成,其中键(key)和值(value)由等号(
=
)连接。 - 编码:所有键和值都必须进行百分比编码(也称为 URL 编码),以确保特殊字符可以安全地传输。
- 分隔:键值对之间通过和号(
&
)分隔。 - 兼容性:几乎所有的服务器端语言和框架都支持这种格式,因此它具有很好的兼容性。
示例:
假设有一个表单,包含用户名和密码字段,用户填写后提交到服务器:
<form action="/submit" method="post"> <input type="text" name="username" value="user123"> <input type="password" name="password" value="pass123"> <input type="submit" value="Submit"> </form>
当用户提交这个表单时,浏览器会将数据编码成以下格式:
username=user123&password=pass123
HTTP 请求示例:
POST /submit HTTP/1.1 Host: example.com Content-Type: application/x-www-form-urlencoded username=user123&password=pass123
与传统表单格式相比的 JSON:
- 结构:JSON 是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成。
- 格式:JSON 数据是自描述的,由键值对组成,键是字符串,值可以是字符串、数字、数组、布尔值或其他 JSON 对象。
- 数据类型:JSON 支持更丰富的数据类型,如数组和嵌套对象。
- 使用场景:JSON 通常用于 API 通信,特别是 RESTful API。
JSON 请求示例:
POST /api/register HTTP/1.1 Host: example.com Content-Type: application/json; charset=utf-8 { "username": "user123", "password": "pass123" }
在现代 Web 应用和 API 开发中,JSON 格式因其结构化和易于处理的特点而变得越来越流行,尤其是在需要传输复杂数据结构时。然而,传统的表单格式由于其简单性和广泛的支持,仍然在特定场景下被广泛使用。