HttpClient详解

HttpClient学习

1. 导入需要的pom文件

   <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.12</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastJson</artifactId>
            <version>1.2.7</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.16</version>
        </dependency>
        <!--如果需要灵活的传输文件,引入此依赖后会更加方便-->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpmime</artifactId>
            <version>4.5.5</version>
        </dependency>
    </dependencies>

2.GET请求的测试

2.1 测试代码
package com.wcc;

import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
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.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

//@SpringBootTest
public class HttpGetTest {

    @Test
    // get的无参方式
    public void getTest001(){
        // 创建httpClient客户端(可以理解为在这里创建一个浏览器,来发送请求,但是并不同于浏览器)
        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
        // 创建get请求
        HttpGet httpGet = new HttpGet("http://localhost:20000/getTest01");
        // 声明响应模型
        CloseableHttpResponse httpResponse = null;
        try {
            // 客户端发送get请求
            httpResponse = httpClient.execute(httpGet);
            // 从响应模型中获得具体的实体
            HttpEntity entity = httpResponse.getEntity();
            System.out.println("响应状态为"+httpResponse.getStatusLine());
            if (entity!=null){
                System.out.println("响应的内容长度为"+entity.getContentLength());
                System.out.println("响应内容为"+ EntityUtils.toString(entity));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Test
    // get的有参方式
    public void getTest002(){
        //构建httpClient对象
        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
        // 构建参数
        StringBuffer sb =new StringBuffer();

        // 字符数据最好encoding以下;这样一来,某些特殊字符才能传过去(如:某人的名字就是“&”,不encoding的话,传不过去)
        // sb.append("name="+ URLEncoder.encode("&","utf-8"));
        sb.append("name=xiaoliu");
        sb.append("&");
        sb.append("age=18");
        String url = "http://localhost:20000/getTest02?" + sb;
        System.out.println("请求的地址为"+url);
        HttpGet httpGet = new HttpGet(url);
        // 配置信息
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectionRequestTimeout(5000) // 设置请求超时时间
                .setConnectTimeout(5000)           // 设置连接超时时间
                .setSocketTimeout(5000)            // socket读写超时时间
                .setRedirectsEnabled(true)
                .build();
        // 将上面的配置信息,运用到这个get请求中
        httpGet.setConfig(requestConfig);
        // 声明响应模型
        CloseableHttpResponse httpResponse = null;
        try {
            // 执行此get请求
            httpResponse = httpClient.execute(httpGet);
            // 获取响应实体
            HttpEntity entity = httpResponse.getEntity();
            System.out.println("请求的响应状态为"+httpResponse.getStatusLine());
            if (entity != null){
                System.out.println("响应的实体长度为"+entity.getContentLength());
                System.out.println("响应的内容为"+EntityUtils.toString(entity));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Test
    // get的有参方式二
    public void getTest003(){
        // 构建httpClient对象
        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
        // 参数URL
        URI uri = null;
        // 将参数放入键值对namevaluepair中,再放入集合中
        List<NameValuePair> params = new ArrayList<>();
        params.add(new BasicNameValuePair("name","wang"));
        params.add(new BasicNameValuePair("age","18"));
        // 设置uri信息,并将参数集合放入uri;
        // 注:这里也支持一个键值对一个键值对地往里面放setParameter(String key, String value)
        try {
            uri = new URIBuilder().setScheme("http").setHost("localhost").setPort(20000)
                    .setPath("getTest02").setParameters(params).build();
            HttpGet httpGet = new HttpGet(uri);
            // 设置配置信息
            RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(5000)
                    .setConnectTimeout(5000).setConnectionRequestTimeout(5000).build();
            // 将此配置信息,运用到此请求中
            httpGet.setConfig(requestConfig);
            try {
                // 执行此请求 返回响应对象
                CloseableHttpResponse httpResponse = httpClient.execute(httpGet);
                // 获取响应实体
                HttpEntity entity = httpResponse.getEntity();
                System.out.println("响应状态为"+httpResponse.getStatusLine());
                if ( entity != null){
                    System.out.println("响应内容的长度为:"+entity.getContentLength());
                    System.out.println("响应内容为:"+EntityUtils.toString(entity));
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
    }

}

2.2 对应的控制层代码
@RestController
public class HttpClentGetTest {

    @RequestMapping(value = "getTest01",method = RequestMethod.GET)
    public String doGetTest01(){
        return "123";
    }

    @RequestMapping(value = "getTest02",method = RequestMethod.GET)
    public String doGetTest02(String name,int age){
        return name +"已经"+age+"岁了";
    }
}

3.POST请求

3.1 测试代码
package com.wcc;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.sun.org.apache.bcel.internal.generic.NEW;
import com.wcc.pojo.User;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

public class HttpPostTest {

    @Test
    // 无参的post请求
    public void postTest01(){
        // 构建httpClient客户端
        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
        // 创建httppost请求
        HttpPost httpPost = new HttpPost("http://localhost:20000/postTest001");
        try {
            // 执行此请求
            CloseableHttpResponse httpResponse = httpClient.execute(httpPost);
            // 获取响应实体
            HttpEntity entity = httpResponse.getEntity();
            System.out.println("响应的状态为:"+httpResponse.getStatusLine());
            if (entity != null){
                System.out.println("响应的内容长度:"+entity.getContentLength());
                System.out.println("响应的内容为"+ EntityUtils.toString(entity));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    @Test
    // 有参的post请求方式
    public void postTest002(){
        // 获取httpClient对象
        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
        // 构建参数
        StringBuffer params = new StringBuffer();
        params.append("name=xiaoliu").append("&").append("doing=昨晚腰疼");
        HttpPost httpPost = new HttpPost("http://localhost:20000/postTest002?" + params);
        try {
            // 设置ContentType(注:如果只是传普通参数的话,ContentType不一定非要用application/json)
            httpPost.setHeader("Content-Type","application/json;charset=utf-8");
            // 执行httpPost请求
            CloseableHttpResponse httpResponse = httpClient.execute(httpPost);
            // 获取实体
            HttpEntity entity = httpResponse.getEntity();
            System.out.println("响应状态为"+httpResponse.getStatusLine());
            if ( entity!=null ){
                System.out.println("响应内容长度为"+entity.getContentLength());
                System.out.println("响应的内容为"+EntityUtils.toString(entity));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    @Test
    // 有参的post请求 构建参数的第二种方式
    public void postTest003(){
        // 获取客户端
        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
        // 构建参数
        List<NameValuePair> params = new ArrayList<>();
        params.add(new BasicNameValuePair("name","小王"));
        params.add(new BasicNameValuePair("doing","xuexi"));
        try {
            // 构建URI
            URI uri = new URIBuilder().setScheme("http").setHost("localhost").setPort(20000).setPath("postTest002")
                    .setParameters(params).build();
            // 构建post请求
            HttpPost httpPost = new HttpPost(uri);
            // 发送请求
            CloseableHttpResponse httpResponse = httpClient.execute(httpPost);
            System.out.println("响应状态为:"+httpResponse.getStatusLine());
            HttpEntity entity = httpResponse.getEntity();
            if ( entity!= null){
                System.out.println("响应内容长度为:"+entity.getContentLength());
                System.out.println("我告诉你一个秘密:"+EntityUtils.toString(entity));
            }
        } catch (URISyntaxException | IOException e) {
            e.printStackTrace();
        }
    }

    // post请求参数为一个对象时
    @Test
    public void testPost004(){
        // 构建httpClient对象
        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
        // 构建参数
        User user = new User().setId(1).setName("小刘").setAge(18);
        String jsonString = JSON.toJSONString(user);
        StringEntity stringEntity = new StringEntity(jsonString, "utf-8");
        // 构建post请求
        HttpPost httpPost = new HttpPost("http://localhost:20000/postTest003");
        httpPost.setEntity(stringEntity);
        httpPost.setHeader("Content-Type","application/json;charset=utf-8");
        try {
            // 执行post请求
            CloseableHttpResponse httpResponse = httpClient.execute(httpPost);
            HttpEntity entity = httpResponse.getEntity();
            System.out.println("详情:"+EntityUtils.toString(entity));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 普通参数和对象参数
    @Test
    public void postTest005(){
        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
        List<NameValuePair> params = new ArrayList<>();
        params.add(new BasicNameValuePair("name","xiaoliu"));
        try {
            URI uri = new URIBuilder().setScheme("http").setHost("localhost").setPort(20000).
                    setPath("postTest004").setParameters(params).build();
            User user = new User().setName("xiaoliu");
            HttpPost httpPost = new HttpPost(uri);
            httpPost.setEntity(new StringEntity(JSON.toJSONString(user),"utf-8"));
            // 如果请求参数为对象。必须设置这个json传参
            httpPost.setHeader("Content-Type","application/json;charset=utf-8");
            CloseableHttpResponse httpResponse = httpClient.execute(httpPost);
            System.out.println("响应状态为:"+httpResponse.getStatusLine());
            HttpEntity entity = httpResponse.getEntity();
            if ( entity!=null ){
                // 防止乱码,解决方式
                System.out.println("响应内容为"+EntityUtils.toString(entity, StandardCharsets.UTF_8));
            }
        } catch (URISyntaxException e) {
            e.printStackTrace();
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

3.2 对应的控制层代码
@RestController
public class HttpClientPostTest {

    @PostMapping(value = "postTest001")
    public String postTest001(){
        return "无参的post请求";
    }

    @PostMapping(value = "postTest002")
    public String postTest002(String name,String doing){
        return name+doing;
    }

    @PostMapping(value = "postTest003")
    public String postTest003(@RequestBody User user){
        if (user.getName().equalsIgnoreCase("xiaoliu")){
            return "lovely";
        }
        return "笨";
    }

    @PostMapping(value = "postTest004")
    public String postTest004(String name,@RequestBody User user){
        if (name.equalsIgnoreCase(user.getName())){
            return "benbenbenben";
        }
        return "congming";
    }
}
3.3 对应的实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class User {
    private int id;
    private String name;
    private int age;
}

4.Http上传文件

4.1 测试代码
public class FileTest {
    // 上传文件对应的测试
    @Test
    public void fileTest() throws IOException {
        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
        HttpPost httpPost = new HttpPost("http://localhost:20000/file");
        MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
        // 第一个文件
        String fileKey = "files";
        File file1 = new File("D:\\360Downloads\\111.jpg");
        multipartEntityBuilder.addBinaryBody(fileKey,file1);
        // 第二个文件(多个文件的话,使用同一个key就行,后端用数组或者集合接受即可)
        File file2 = new File("D:\\360Downloads\\timg.png");
        // 防止服务端收到的文件名乱码。 我们这里可以先将文件名URLEncode,然后服务端拿到文件名时在URLDecode。就能避免乱码问题。
        // 文件名其实是放在请求头的Content-Disposition里面进行传输的,如其值为form-data; name="files"; filename=timg.png"
        multipartEntityBuilder.addBinaryBody(fileKey,file2, ContentType.DEFAULT_BINARY, URLEncoder.encode(file2.getName(),"utf-8"));
        // 其他参数
        multipartEntityBuilder.addTextBody("name","xiaowang",ContentType.DEFAULT_TEXT);
        multipartEntityBuilder.addTextBody("age","18",ContentType.DEFAULT_TEXT);
        HttpEntity httpEntity = multipartEntityBuilder.build();
        httpPost.setEntity(httpEntity);
        // 执行
        CloseableHttpResponse httpResponse = httpClient.execute(httpPost);
        System.out.println("响应的状态为:"+httpResponse.getStatusLine());
        HttpEntity entity = httpResponse.getEntity();
        if ( entity!=null ){
            System.out.println("响应内容为:"+ EntityUtils.toString(entity));
        }
    }
}

4.2 controller层代码
@RestController
public class FileController {

    @PostMapping(value = "file")
    public String fileTest001(@RequestParam("name")String name,
                              @RequestParam("age") int age,
                              @RequestParam("files")MultipartFile[] multipartFiles) throws IOException {
        if (multipartFiles.length>0){
            for (MultipartFile multipartFile : multipartFiles) {
                InputStream inputStream = multipartFile.getInputStream();
                IOUtils.copy(inputStream,new FileOutputStream(new File(multipartFile.getOriginalFilename())));
                return "success";
            }
        }
        return "nonononon";
    }
}

5.Http发送流的测试

5.1 测试代码
public class StreamTest {
    // 发送流测试
    @Test
    public void streamTest() throws IOException {
        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
        HttpPost httpPost = new HttpPost("http://localhost:20000/stream?name=xiowangshuo");
        InputStream inputStream = new ByteArrayInputStream("nihaoya,xiaoliu".getBytes());
        InputStreamEntity streamEntity = new InputStreamEntity(inputStream);
        httpPost.setEntity(streamEntity);
        CloseableHttpResponse httpResponse = httpClient.execute(httpPost);
        HttpEntity entity = httpResponse.getEntity();
        if ( entity!=null ){
            System.out.println("响应内容为:"+ EntityUtils.toString(entity));
        }
    }
}
5.2controller层代码
@RestController
public class StreamController {
    @PostMapping(value = "stream")
    public String streamTest(@RequestParam("name") String name, InputStream inputStream) throws IOException {
        StringBuffer sb = new StringBuffer();
        sb.append("name的值为").append(name);
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        String line;
        while ( (line=reader.readLine())!= null){
            sb.append(line);
        }
        return sb.toString();
    }
}

6.Https测试

package com.wcc;

import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.io.InputStream;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Arrays;

public class HttpsTest {
    /**
     * 根据是否是https请求,获取HttpClient客户端
     * 提示: 此工具类的封装、相关客户端、服务端证书的生成,可参考这篇博客:
     *      <linked>https://blog.csdn.net/justry_deng/article/details/91569132</linked>
     * @param isHttps 是否是HTTPS请求
     * @return  HttpClient实例
     * @date 2019/9/18 17:57
     */
    private CloseableHttpClient getHttpClient(boolean isHttps) {
        CloseableHttpClient httpClient;
        if (isHttps) {
            SSLConnectionSocketFactory sslSocketFactory;
            try {
                /// 如果不作证书校验的话
                sslSocketFactory = getSocketFactory(false, null, null);

                /// 如果需要证书检验的话
                // 证书
                //InputStream ca = this.getClass().getClassLoader().getResourceAsStream("client/ds.crt");
                // 证书的别名,即:key。 注:cAalias只需要保证唯一即可,不过推荐使用生成keystore时使用的别名。
                // String cAalias = System.currentTimeMillis() + "" + new SecureRandom().nextInt(1000);
                //sslSocketFactory = getSocketFactory(true, ca, cAalias);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            httpClient = HttpClientBuilder.create().setSSLSocketFactory(sslSocketFactory).build();
            return httpClient;
        }
        httpClient = HttpClientBuilder.create().build();
        return httpClient;
    }

    /**
     * HTTPS辅助方法, 为HTTPS请求 创建SSLSocketFactory实例、TrustManager实例
     *
     * @param needVerifyCa
     *         是否需要检验CA证书(即:是否需要检验服务器的身份)
     * @param caInputStream
     *         CA证书。(若不需要检验证书,那么此处传null即可)
     * @param cAalias
     *         别名。(若不需要检验证书,那么此处传null即可)
     *         注意:别名应该是唯一的, 别名不要和其他的别名一样,否者会覆盖之前的相同别名的证书信息。别名即key-value中的key。
     *
     * @return SSLConnectionSocketFactory实例
     * @throws NoSuchAlgorithmException
     *         异常信息
     * @throws CertificateException
     *         异常信息
     * @throws KeyStoreException
     *         异常信息
     * @throws IOException
     *         异常信息
     * @throws KeyManagementException
     *         异常信息
     * @date 2019/6/11 19:52
     */
    private static SSLConnectionSocketFactory getSocketFactory(boolean needVerifyCa, InputStream caInputStream, String cAalias)
            throws CertificateException, NoSuchAlgorithmException, KeyStoreException,
            IOException, KeyManagementException {
        X509TrustManager x509TrustManager;
        // https请求,需要校验证书
        if (needVerifyCa) {
            KeyStore keyStore = getKeyStore(caInputStream, cAalias);
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(keyStore);
            TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
            if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
                throw new IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustManagers));
            }
            x509TrustManager = (X509TrustManager) trustManagers[0];
            // 这里传TLS或SSL其实都可以的
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, new TrustManager[]{x509TrustManager}, new SecureRandom());
            return new SSLConnectionSocketFactory(sslContext);
        }
        // https请求,不作证书校验
        x509TrustManager = new X509TrustManager() {
            @Override
            public void checkClientTrusted(X509Certificate[] arg0, String arg1) {
            }

            @Override
            public void checkServerTrusted(X509Certificate[] arg0, String arg1) {
                // 不验证
            }

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[0];
            }
        };
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, new TrustManager[]{x509TrustManager}, new SecureRandom());
        return new SSLConnectionSocketFactory(sslContext);
    }

    /**
     * 获取(密钥及证书)仓库
     * 注:该仓库用于存放 密钥以及证书
     *
     * @param caInputStream
     *         CA证书(此证书应由要访问的服务端提供)
     * @param cAalias
     *         别名
     *         注意:别名应该是唯一的, 别名不要和其他的别名一样,否者会覆盖之前的相同别名的证书信息。别名即key-value中的key。
     * @return 密钥、证书 仓库
     * @throws KeyStoreException 异常信息
     * @throws CertificateException 异常信息
     * @throws IOException 异常信息
     * @throws NoSuchAlgorithmException 异常信息
     * @date 2019/6/11 18:48
     */
    private static KeyStore getKeyStore(InputStream caInputStream, String cAalias)
            throws KeyStoreException, CertificateException, IOException, NoSuchAlgorithmException {
        // 证书工厂
        CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
        // 秘钥仓库
        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        keyStore.load(null);
        keyStore.setCertificateEntry(cAalias, certificateFactory.generateCertificate(caInputStream));
        return keyStore;
    }
}

Http封装好的工具类 github地址:https://github.com/Arronlong/httpclientutil
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值