HttpClient

简介

  HTTP 协议可能是现在 Internet 上使用得最多、最重要的协议了,越来越多的 Java 应用程序需要直接通过 HTTP 协议来访问网络资源。虽然在 JDK 的 java.net 包中已经提供了访问 HTTP 协议的基本功能,但是对于大部分应用程序来说,JDK 库本身提供的功能还不够丰富和灵活。HttpClient 是 Apache Jakarta Common 下的子项目,用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。

        HTTP 和浏览器有点像,但却不是浏览器。很多人觉得既然 HttpClient 是一个 HTTP 客户端编程工具,很多人把他当做浏览器来理解,但是其实 HttpClient 不是浏览器,它是一个 HTTP 通信库,因此它只提供一个通用浏览器应用程序所期望的功能子集,最根本的区别是 HttpClient  中没有用户界面,浏览器需要一个渲染引擎来显示页面,并解释用户输入,例如鼠标点击显示页面上的某处,有一个布局引擎,计算如何显示 HTML 页面,包括级联样式表和图像。javascript 解释器运行嵌入 HTML 页面或从 HTML 页面引用的 javascript 代码。来自用户界面的事件被传递到 javascript 解释器进行处理。除此之外,还有用于插件的接口,可以处理 Applet,嵌入式媒体对象(如 pdf 文件,Quicktime 电影和 Flash 动画)或 ActiveX 控件(可以执行任何操作)。HttpClient 只能以编程的方式通过其 API 用于传输和接受 HTTP 消息。

HttpClient 的主要功能:

  • 实现了所有 HTTP 的方法(GET、POST、PUT、HEAD、DELETE、HEAD、OPTIONS 等)
  • 支持 HTTPS 协议
  • 支持代理服务器(Nginx 等)等
  • 支持自动(跳转)转向
  • ……

环境说明:JDK1.8、SpringBoot

准备环节

引入依赖

<!-- fastjson -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.47</version>
</dependency>

<!-- httpclient -->
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.5</version>
</dependency>

注意:

  • 本人引入此依赖的目的是,在后续示例中,会用到“将对象转化为 json 字符串的功能”,也可以引其他有此功能的依赖。
  • SpringBoot 的基本依赖配置,这里就不再多说了。

详细使用示例

声明:此示例中,以 JAVA 发送 HttpClient(在 test 里面单元测试发送的);也是以 JAVA 接收的(在 controller 里面接收的)。

声明:下面的代码,本人亲测有效。注意:函数中的异常没有捕获,正常情况需要捕获,且资源关闭需要放到 finally 中。

GET 无参

HttpClient 发送示例:

/**
 * GET---无参测试
 */
@Test
public void doGetTestOne() throws Exception {
    // 获得Http客户端(可以理解为:你得先有一个浏览器;注意:实际上HttpClient与浏览器是不一样的)
    CloseableHttpClient httpClient = HttpClientBuilder.create().build();
    // 创建Get请求
    HttpGet httpGet = new HttpGet("http://127.0.0.1:8888/doGetControllerOne");

    // 响应模型
    CloseableHttpResponse response = httpClient.execute(httpGet);// 由客户端执行(发送)Get请求
    // 从响应模型中获取响应实体
    HttpEntity responseEntity = response.getEntity();
    System.out.println("响应状态为:" + response.getStatusLine());
    if (responseEntity != null) {
        System.out.println("响应内容长度为:" + responseEntity.getContentLength());
        System.out.println("响应内容为:" + EntityUtils.toString(responseEntity));
    }
    if (response != null) {
        response.close();
    }
    // 释放资源
    if (httpClient != null) {
        httpClient.close();
    }
}

接收示例:

/**
 * GET无参
 */
@RequestMapping("/doGetControllerOne")
public String doGetControllerOne() {
    return "123";
}

控制台打印:

响应状态为:HTTP/1.1 200 
响应内容长度为:3
响应内容为:123

GET有参(方式一:直接拼接URL)

HttpClient 发送示例:

/**
 * GET---有参测试 (方式一:手动在url后面加上参数)
 */
@Test
public void doGetTestWayOne() throws Exception {
    // 获得Http客户端(可以理解为:你得先有一个浏览器;注意:实际上HttpClient与浏览器是不一样的)
    CloseableHttpClient httpClient = HttpClientBuilder.create().build();

    // 参数
    StringBuilder params = new StringBuilder();
    // 字符数据最好encoding以下;这样一来,某些特殊字符才能传过去(如:某人的名字就是“&”,不encoding的话,传不过去)
    params.append("name=").append(URLEncoder.encode("张三", "utf-8"));
    params.append("&");
    params.append("age=24");

    // 创建Get请求
    HttpGet httpGet = new HttpGet("http://localhost:8888/doGetControllerTwo" + "?" + params);
    // 响应模型
    CloseableHttpResponse response = null;
    // 配置信息
    RequestConfig requestConfig = RequestConfig.custom()
            // 设置连接超时时间(单位毫秒)
            .setConnectTimeout(5000)
            // 设置请求超时时间(单位毫秒)
            .setConnectionRequestTimeout(5000)
            // socket读写超时时间(单位毫秒)
            .setSocketTimeout(5000)
            // 设置是否允许重定向(默认为true)
            .setRedirectsEnabled(true).build();

    // 将上面的配置信息 运用到这个Get请求里
    httpGet.setConfig(requestConfig);

    // 由客户端执行(发送)Get请求
    response = httpClient.execute(httpGet);
    // 从响应模型中获取响应实体
    HttpEntity responseEntity = response.getEntity();
    System.out.println("响应状态为:" + response.getStatusLine());
    if (responseEntity != null) {
        System.out.println("响应内容长度为:" + responseEntity.getContentLength());
        System.out.println("响应内容为:" + EntityUtils.toString(responseEntity));
    }
    if (response != null) {
        response.close();
    }
    // 释放资源
    if (httpClient != null) {
        httpClient.close();
    }
}

接收示例:

/**
 * GET有参
 */
@RequestMapping("/doGetControllerTwo")
public String doGetControllerTwo(String name, Integer age) {
    return "没想到[" + name + "]都" + age + "岁了!";
}

控制台打印:

响应状态为:HTTP/1.1 200 
响应内容长度为:29
响应内容为:没想到[张三]都24岁了!

GET 有参(方式二:使用 URI 获得 HttpGet)

HttpClient 发送示例:

/**
 * GET---有参测试 (方式二:将参数放入键值对类中,再放入URI中,从而通过URI得到HttpGet实例)
 */
@Test
public void doGetTestWayTwo() throws Exception {
    // 获得Http客户端(可以理解为:你得先有一个浏览器;注意:实际上HttpClient与浏览器是不一样的)
    CloseableHttpClient httpClient = HttpClientBuilder.create().build();

    // 参数
    URI uri = null;
    // 将参数放入键值对类NameValuePair中,再放入集合中
    List<NameValuePair> params = new ArrayList<>();
    params.add(new BasicNameValuePair("name", "&"));
    params.add(new BasicNameValuePair("age", "18"));
    // 设置uri信息,并将参数集合放入uri;
    // 注:这里也支持一个键值对一个键值对地往里面放setParameter(String key, String value)
    uri = new URIBuilder().setScheme("http").setHost("localhost")
            .setPort(8888).setPath("/doGetControllerTwo")
            .setParameters(params).build();
    // 创建Get请求
    HttpGet httpGet = new HttpGet(uri);

    // 响应模型
    CloseableHttpResponse response = null;
    // 配置信息
    RequestConfig requestConfig = RequestConfig.custom()
            // 设置连接超时时间(单位毫秒)
            .setConnectTimeout(5000)
            // 设置请求超时时间(单位毫秒)
            .setConnectionRequestTimeout(5000)
            // socket读写超时时间(单位毫秒)
            .setSocketTimeout(5000)
            // 设置是否允许重定向(默认为true)
            .setRedirectsEnabled(true).build();

    // 将上面的配置信息 运用到这个Get请求里
    httpGet.setConfig(requestConfig);

    // 由客户端执行(发送)Get请求
    response = httpClient.execute(httpGet);
    // 从响应模型中获取响应实体
    HttpEntity responseEntity = response.getEntity();
    System.out.println("响应状态为:" + response.getStatusLine());
    if (responseEntity != null) {
        System.out.println("响应内容长度为:" + responseEntity.getContentLength());
        System.out.println("响应内容为:" + EntityUtils.toString(responseEntity));
    }
    // 释放资源
    if (httpClient != null) {
        httpClient.close();
    }
    if (response != null) {
        response.close();
    }
}

接收示例:同上

控制台打印:

响应状态为:HTTP/1.1 200 
响应内容长度为:24
响应内容为:没想到[&]都18岁了!

POST 无参

HttpClient 发送示例:

/**
 * POST---无参测试
 */
@Test
public void doPostTestOne() throws Exception {

    // 获得Http客户端(可以理解为:你得先有一个浏览器;注意:实际上HttpClient与浏览器是不一样的)
    CloseableHttpClient httpClient = HttpClients.createDefault();

    // 创建Post请求
    HttpPost httpPost = new HttpPost("http://localhost:8888/doPostControllerOne");
    // 响应模型
    CloseableHttpResponse response = httpClient.execute(httpPost);// 由客户端执行(发送)Post请求
    // 从响应模型中获取响应实体
    HttpEntity responseEntity = response.getEntity();

    System.out.println("响应状态为:" + response.getStatusLine());
    if (responseEntity != null) {
        System.out.println("响应内容长度为:" + responseEntity.getContentLength());
        System.out.println("响应内容为:" + EntityUtils.toString(responseEntity));
    }

    // 释放资源
    if (response != null) {
        response.close();
    }
    if (httpClient != null) {
        httpClient.close();
    }
}

接收示例:

/**
 * POST无参
 */
@RequestMapping(value = "/doPostControllerOne", method = RequestMethod.POST)
public String doPostControllerOne() {
    return "这个post请求没有任何参数!";
}

控制台打印:

响应状态为:HTTP/1.1 200 
响应内容长度为:35
响应内容为:这个post请求没有任何参数!

POST 有参(普通参数,方式一:直接拼接URL)

注:POST 传递普通参数时,方式与 GET 一样即可,这里以直接在 url 后缀上参数的方式示例。

HttpClient 发送示例:

/**
 * POST---有参测试(基本参数)
 */
@Test
public void doPostTestFour() throws Exception {
    // 获得Http客户端(可以理解为:你得先有一个浏览器;注意:实际上HttpClient与浏览器是不一样的)
    CloseableHttpClient httpClient = HttpClientBuilder.create().build();

    // 参数
    StringBuilder params = new StringBuilder();
    // 字符数据最好encoding以下;这样一来,某些特殊字符才能传过去(如:某人的名字就是“&”,不encoding的话,传不过去)
    params.append("name=").append(URLEncoder.encode("&", "utf-8"));
    params.append("&");
    params.append("age=24");

    // 创建Post请求
    HttpPost httpPost = new HttpPost("http://localhost:8888/doPostControllerFour" + "?" + params);

    // 设置ContentType(注:如果只是传普通参数的话,ContentType不一定非要用application/json)
    httpPost.setHeader("Content-Type", "application/json;charset=utf8");

    // 响应模型
    CloseableHttpResponse response = null;
    // 由客户端执行(发送)Post请求
    response = httpClient.execute(httpPost);
    // 从响应模型中获取响应实体
    HttpEntity responseEntity = response.getEntity();

    System.out.println("响应状态为:" + response.getStatusLine());
    if (responseEntity != null) {
        System.out.println("响应内容长度为:" + responseEntity.getContentLength());
        System.out.println("响应内容为:" + EntityUtils.toString(responseEntity));
    }

    // 释放资源
    if (response != null) {
        response.close();
    }
    if (httpClient != null) {
        httpClient.close();
    }
}

接收示例:

/**
 * POST有参(普通参数)
 */
@RequestMapping(value = "/doPostControllerFour", method = RequestMethod.POST)
public String doPostControllerThree1(String name, Integer age) {
    return "[" + name + "]居然才[" + age + "]岁!!!";
}

控制台打印:

响应状态为:HTTP/1.1 200 
响应内容长度为:22
响应内容为:[&]居然才[24]岁!!!

POST 有参(普通参数,方式二:setEntity)

/**
 * POST有参(普通参数)
 */
@Test
public void doPostTestFour2() throws Exception {
    // 创建默认的httpClient实例.
    CloseableHttpClient httpClient = HttpClients.createDefault();
    // 创建httppost
    HttpPost httppost = new HttpPost("http://localhost:8888/doPostControllerFour");
    // 创建参数队列
    List<NameValuePair> formparams = new ArrayList<NameValuePair>();
    formparams.add(new BasicNameValuePair("name", "&"));
    formparams.add(new BasicNameValuePair("age", "24"));
    UrlEncodedFormEntity uefEntity = new UrlEncodedFormEntity(formparams, "UTF-8");

    httppost.setEntity(uefEntity);
    System.out.println("executing request " + httppost.getURI());
    CloseableHttpResponse response = httpClient.execute(httppost);
    HttpEntity responseEntity = response.getEntity();
    System.out.println("响应状态为:" + response.getStatusLine());
    if (responseEntity != null) {
        System.out.println("响应内容长度为:" + responseEntity.getContentLength());
        System.out.println("响应内容为:" + EntityUtils.toString(responseEntity));
    }

    // 释放资源
    if (response != null) {
        response.close();
    }
    if (httpClient != null) {
        httpClient.close();
    }
}

接收示例和控制台打印同上

POST 有参(对象参数)

先给出 User 类

/**
 * 用户实体类模型
 */
public class User {

    /**
     * 姓名
     */
    private String name;

    /**
     * 年龄
     */
    private Integer age;

    /**
     * 性别
     */
    private String gender;

    /**
     * 座右铭
     */
    private String motto;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public String getMotto() {
        return motto;
    }

    public void setMotto(String motto) {
        this.motto = motto;
    }

    @Override
    public String toString() {
        return age + "岁" + gender + "人[" + name + "]的座右铭居然是: " + motto + "!!!";
    }

}
User 类

HttpClient 发送示例:

/**
 * POST---有参测试(对象参数)
 */
@Test
public void doPostTestTwo() throws Exception {

    // 获得Http客户端(可以理解为:你得先有一个浏览器;注意:实际上HttpClient与浏览器是不一样的)
    CloseableHttpClient httpClient = HttpClientBuilder.create().build();

    // 创建Post请求
    HttpPost httpPost = new HttpPost("http://localhost:8888/doPostControllerTwo");
    User user = new User();
    user.setName("潘晓婷");
    user.setAge(18);
    user.setGender("女");
    user.setMotto("姿势要优雅~");
    // 我这里利用阿里的fastjson,将Object转换为json字符串;
    // (需要导入com.alibaba.fastjson.JSON包)
    String jsonString = JSON.toJSONString(user);

    StringEntity entity = new StringEntity(jsonString, "UTF-8");

    // post请求是将参数放在请求体里面传过去的;这里将entity放入post请求体中
    httpPost.setEntity(entity);

    httpPost.setHeader("Content-Type", "application/json;charset=utf8");

    // 响应模型
    CloseableHttpResponse response = httpClient.execute(httpPost);// 由客户端执行(发送)Post请求
    // 从响应模型中获取响应实体
    HttpEntity responseEntity = response.getEntity();

    System.out.println("响应状态为:" + response.getStatusLine());
    if (responseEntity != null) {
        System.out.println("响应内容长度为:" + responseEntity.getContentLength());
        System.out.println("响应内容为:" + EntityUtils.toString(responseEntity));
    }
    // 释放资源
    if (response != null) {
        response.close();
    }
    if (httpClient != null) {
        httpClient.close();
    }
}

接收示例:

/**
 * POST有参(对象参数)
 */
@RequestMapping(value = "/doPostControllerTwo", method = RequestMethod.POST)
public String doPostControllerTwo(@RequestBody User user) {
    return user.toString();
}

控制台打印:

响应状态为:HTTP/1.1 200 
响应内容长度为:64
响应内容为:18岁女人[潘晓婷]的座右铭居然是: 姿势要优雅~!!!

POST 有参(普通参数 + 对象参数)

注:POST 传递普通参数时,方式与 GET 一样即可,这里以通过 URI 获得 HttpPost 的方式为例。

HttpClient 发送示例:

/**
 * POST---有参测试(普通参数 + 对象参数)
 */
@Test
public void doPostTestThree() throws Exception {

    // 获得Http客户端(可以理解为:你得先有一个浏览器;注意:实际上HttpClient与浏览器是不一样的)
    CloseableHttpClient httpClient = HttpClientBuilder.create().build();

    // 创建Post请求
    // 参数
    URI uri = null;
    // 将参数放入键值对类NameValuePair中,再放入集合中
    List<NameValuePair> params = new ArrayList<>();
    params.add(new BasicNameValuePair("flag", "4"));
    params.add(new BasicNameValuePair("meaning", "这是什么鬼?"));
    // 设置uri信息,并将参数集合放入uri;
    // 注:这里也支持一个键值对一个键值对地往里面放setParameter(String key, String value)
    uri = new URIBuilder().setScheme("http").setHost("localhost").setPort(8888)
            .setPath("/doPostControllerThree").setParameters(params).build();


    HttpPost httpPost = new HttpPost(uri);

    // 创建user参数
    User user = new User();
    user.setName("潘晓婷");
    user.setAge(18);
    user.setGender("女");
    user.setMotto("姿势要优雅~");

    // 将user对象转换为json字符串,并放入entity中
    StringEntity entity = new StringEntity(JSON.toJSONString(user), "UTF-8");

    // post请求是将参数放在请求体里面传过去的;这里将entity放入post请求体中
    httpPost.setEntity(entity);

    httpPost.setHeader("Content-Type", "application/json;charset=utf8");

    // 响应模型
    CloseableHttpResponse response = null;
    // 由客户端执行(发送)Post请求
    response = httpClient.execute(httpPost);
    // 从响应模型中获取响应实体
    HttpEntity responseEntity = response.getEntity();

    System.out.println("响应状态为:" + response.getStatusLine());
    if (responseEntity != null) {
        System.out.println("响应内容长度为:" + responseEntity.getContentLength());
        System.out.println("响应内容为:" + EntityUtils.toString(responseEntity));
    }

    // 释放资源
    if (response != null) {
        response.close();
    }
    if (httpClient != null) {
        httpClient.close();
    }
}

接收示例:

/**
 * POST有参(普通参数 + 对象参数)
 */
@RequestMapping(value = "/doPostControllerThree", method = RequestMethod.POST)
public String doPostControllerThree(@RequestBody User user,Integer flag, String meaning) {
    return user.toString() + "
" + flag + ">>>" + meaning;
}

控制台打印:

响应状态为:HTTP/1.1 200 
响应内容长度为:87
响应内容为:18岁女人[潘晓婷]的座右铭居然是: 姿势要优雅~!!!
4>>>这是什么鬼?

本文转载自:https://blog.csdn.net/justry_deng/article/details/81042379

参考:https://blog.csdn.net/w372426096/article/details/82713315

原文地址:https://www.cnblogs.com/jwen1994/p/14110368.html