【JavaWeb】HttpClient

 

需要的依赖:

        <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.13</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

 

参考视频:

https://www.bilibili.com/video/BV1W54y1s7BZ

 

1、原生JDK实现的网络请求

这个在狂神的爬虫上面有看到过原生的方式

当时还不明白这个技术其实就是后台的Ajax

    @Test
    public void quickStart() throws IOException {
        InputStream inputStream = null;
        InputStreamReader inputStreamReader = null;
        BufferedReader bufferedReader = null;
        try {

            // 原生JDK API 发送请求
            String urlString = "https://www.baidu.com/";
            URL url = new URL(urlString);
            URLConnection urlConnection = url.openConnection();
            HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection;

            httpURLConnection.setRequestMethod("GET");
            httpURLConnection.setRequestProperty("aaa", "123");

            inputStream = httpURLConnection.getInputStream();
            inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
            bufferedReader = new BufferedReader(inputStreamReader);

            String line = null;
            while (null != ( line = bufferedReader.readLine())) {
                System.out.println(line);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            bufferedReader.close();
            inputStreamReader.close();
            inputStream.close();
        }
    }

 

2、使用ApacheHttpClient发送请求:

    @Test
    public void useHttpClient() throws IOException {
        // 使用 HttpClient Get 无参请求实现

        CloseableHttpClient closeableHttpClient = null;
        CloseableHttpResponse closeableHttpResponse = null;
        HttpEntity httpEntity = null;
        try {
            // 创建一个可关闭的Http客户端对象
            closeableHttpClient = HttpClients.createDefault();

            // 要请求的地址
            String urlString = "https://www.baidu.com/";

            // GET参数需要进行URL编码处理
            String param1 = "orderId=21343000123324";
            String param2 = "orderRemark=大三大四1王企鹅1 哇多久啊是巴西 &%……¥%";
            param1 = URLEncoder.encode(param1, StandardCharsets.UTF_8.name());
            param2 = URLEncoder.encode(param2, StandardCharsets.UTF_8.name());

            // 根据地址创建一个Http请求对象 这里使用的是GET请求对象
            // HttpGet httpGet = new HttpGet(urlString);
            HttpGet httpGet = new HttpGet(urlString + "?" + param1 + "&" + param2);

            // 浏览器伪装信息
            httpGet.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36 Edg/94.0.992.38");

            // 防盗链设置 https://www.jianshu.com/p/0a1338db6cab
            httpGet.addHeader("Referer", "https://ntp.msn.cn/");

            // 客户端对象带着请求对象 执行请求发送, 返回响应对象
            closeableHttpResponse = closeableHttpClient.execute(httpGet);

            // 可以从响应对象获取对应的响应信息
            StatusLine statusLine = closeableHttpResponse.getStatusLine();
            System.out.println(statusLine); // HTTP/1.1 200 OK

            // 响应不成功状态直接结束后续逻辑
            if (HttpStatus.SC_OK != statusLine.getStatusCode()) return;

            ProtocolVersion protocolVersion = statusLine.getProtocolVersion(); // HTTP/1.1
            int major = protocolVersion.getMajor(); // 1 主版本协议号
            int minor = protocolVersion.getMinor(); // 1 附属小版本协议号
            String protocol = protocolVersion.getProtocol(); // HTTP

            int statusCode = statusLine.getStatusCode(); // 200
            String reasonPhrase = statusLine.getReasonPhrase(); // OK

            Header[] allHeaders = closeableHttpResponse.getAllHeaders();
            for (Header header : allHeaders) {
                System.out.println("Response Header -> " + header.getName()  + " : " + header.getValue());
            }
            
            // 从响应对象中获取响应实体对象
            httpEntity = closeableHttpResponse.getEntity();

            Header contentType = httpEntity.getContentType();
            String contentTypeName = contentType.getName(); // Content-Type
            String contentTypeValue = contentType.getValue(); // Content-Type: text/html;charset=utf-8

            // 这个响应头不常见
            // Header contentEncoding = httpEntity.getContentEncoding(); // null
            // String contentEncodingName = contentEncoding.getName();
            // String contentEncodingValue = contentEncoding.getValue();

            // 使用实体工具类转换成字符结果
            String httpEntityResult = EntityUtils.toString(httpEntity, StandardCharsets.UTF_8);
            // System.out.println(httpEntityResult);

        } catch (Exception exception) {
            exception.printStackTrace();
        } finally {
            // 最后调用此方法确保资源释放
            EntityUtils.consume(httpEntity);
            closeableHttpResponse.close();
            closeableHttpClient.close();
        }
    }

 

3、下载图片资源:

    @Test
    public void downloadWebPicture() throws Exception {

        // 请求发送
        CloseableHttpClient closeableHttpClient = HttpClients.createDefault();
        String resource = "https://img.zcool.cn/community/01088b5a052431a801204a0e253198.jpg@1280w_1l_2o_100sh.jpg";
        HttpGet httpGet = new HttpGet(resource);
        CloseableHttpResponse closeableHttpResponse = closeableHttpClient.execute(httpGet);
        HttpEntity httpEntity = closeableHttpResponse.getEntity();

        // 类型解析
        Header contentType = httpEntity.getContentType();
        String contentTypeValue = contentType.getValue(); // image/jpeg
        String fileTypeSuffix = contentTypeValue.split("/")[1]; // jpeg

        // 文件下载
        byte[] bytes = EntityUtils.toByteArray(httpEntity);
        String localPath = "C:\\Users\\Administrator\\Desktop\\test." + fileTypeSuffix;
        OutputStream outputStream = new FileOutputStream(localPath);
        outputStream.write(bytes);

        // 资源释放
        outputStream.close();
        EntityUtils.consume(httpEntity);
        closeableHttpResponse.close();
        closeableHttpClient.close();
    }

 

4、配置代理主机:

    @Test
    public void proxySettings() throws Exception {
        
        CloseableHttpClient closeableHttpClient = HttpClients.createDefault();
        String target = "https://www.baidu.com/";
        HttpGet httpGet = new HttpGet(target);

        // 代理主机的信息 http://www.66ip.cn/
        String ip = "176.121.1.81";
        int port = 8181;
        HttpHost httpHost = new HttpHost(ip, port);

        // 创建请求配置对象
        RequestConfig requestConfig = RequestConfig
                .custom()
                .setProxy(httpHost) // 设置代理主机的信息
                .build();

        // 设置请求配置
        httpGet.setConfig(requestConfig);

        CloseableHttpResponse closeableHttpResponse = closeableHttpClient.execute(httpGet);
        HttpEntity httpEntity = closeableHttpResponse.getEntity();

        Header[] allHeaders = closeableHttpResponse.getAllHeaders();
        for (Header header : allHeaders) {
            System.out.println("Response Header -> " + header.getName()  + " : " + header.getValue());
        }

        String httpEntityResult = EntityUtils.toString(httpEntity, StandardCharsets.UTF_8);
        System.out.println(httpEntityResult);

        // 资源释放
        EntityUtils.consume(httpEntity);
        closeableHttpResponse.close();
        closeableHttpClient.close();
    }

 

5、设置超时相关的配置:

    @Test
    public void proxySettings() throws Exception {
        // 请求发送
        CloseableHttpClient closeableHttpClient = HttpClients.createDefault();
        String target = "https://www.baidu.com/";
        HttpGet httpGet = new HttpGet(target);

        // 代理主机的信息 http://www.66ip.cn/
        String ip = "176.121.1.81";
        int port = 8181;
        HttpHost httpHost = new HttpHost(ip, port);

        // 创建请求配置对象
        RequestConfig requestConfig = RequestConfig
                .custom()
                .setProxy(httpHost)
                .setConnectTimeout(5000) // 设置连接超时的上限 TCP3次握手的时限
                .setSocketTimeout(3000) // 设置读取超时上限  从请求的网址中获取响应数据的间隔时限(因为并不是一次请求就完成了加载)
                .setConnectionRequestTimeout(3000) // 从HttpClient连接池中获取connection对象的时限
                .build();

        // 设置请求配置
        httpGet.setConfig(requestConfig);

        CloseableHttpResponse closeableHttpResponse = closeableHttpClient.execute(httpGet);
        HttpEntity httpEntity = closeableHttpResponse.getEntity();

        Header[] allHeaders = closeableHttpResponse.getAllHeaders();
        for (Header header : allHeaders) {
            System.out.println("Response Header -> " + header.getName()  + " : " + header.getValue());
        }

        String httpEntityResult = EntityUtils.toString(httpEntity, StandardCharsets.UTF_8);
        System.out.println(httpEntityResult);

        // 资源释放
        EntityUtils.consume(httpEntity);
        closeableHttpResponse.close();
        closeableHttpClient.close();
    }

 

6、MIME-TYPE 邮件扩展类型 与POST请求

mime-type 就是具体文件类型的前面的所属规范类型

在Tomcat里面配置的web.xml信息就可以看到所有的规范类型了

E:\apache-tomcat-8.5.70\conf\web.xml

片段:

    <mime-mapping>
        <extension>zirz</extension>
        <mime-type>application/vnd.zul</mime-type>
    </mime-mapping>
    <mime-mapping>
        <extension>zmm</extension>
        <mime-type>application/vnd.handheld-entertainment+xml</mime-type>
    </mime-mapping>

 

常见Content-type:

# 一般html表单提交 发送的类型
application/x-www-form-urlencoded

# html上传文件规范的类型
multipart/form-data

# 目前主流规范的类型
application/json

 

POST表单类型提交案例:

1、客户端请求代码

    @Test
    public void postWithFormType() throws Exception {
        CloseableHttpClient closeableHttpClient = HttpClients.createDefault();
        String target = "http://localhost:8080/mvc-framework/test/testMethod2";

        // 首先创建POST请求对象
        HttpPost httpPost = new HttpPost(target);


        // 设置表单需要提交的参数
        List<NameValuePair> nvpList = new ArrayList<>();
        nvpList.add(new BasicNameValuePair("username", "张三"));
        nvpList.add(new BasicNameValuePair("password", "w123e21"));

        // 表单类型实体对象 装填参数信息 application/x-www-form-urlencoded
        UrlEncodedFormEntity urlEncodedFormEntity = new UrlEncodedFormEntity(nvpList, Consts.UTF_8);

// 设置表单类型实体对象
        httpPost.setEntity(urlEncodedFormEntity);

        // 客户端执行请求发送
        CloseableHttpResponse closeableHttpResponse = closeableHttpClient.execute(httpPost);
        HttpEntity httpEntity = closeableHttpResponse.getEntity();
        System.out.println(EntityUtils.toString(httpEntity, StandardCharsets.UTF_8));

        EntityUtils.consume(httpEntity);
        closeableHttpResponse.close();
        closeableHttpClient.close();
    }

2、服务器处理代码:

    /**
     *
     *  POST请求测试
     *  http://localhost:8080/mvc-framework/test/testMethod2
     * @param request
     * @param response
     */
    // @RequestMethod(MethodType.POST)
    @RequestMapping(value = "/testMethod2", methodType = MethodType.POST)
    public void testMethod2(HttpServletRequest request, HttpServletResponse response) {
        System.out.println("testMethod2");

        ServletUtil.printAllParamByRequestMap(request);

        Map<String, Object> requestAttribute = (Map<String, Object>) request.getAttribute(ServletConstants.POST_PARAM_KEY);

        for (String s : requestAttribute.keySet()) {
            System.out.println("postParam " + s + ": " + requestAttribute.get(s));
        }
    }

服务这里没有对请求做出响应,就是打印看看没有收到参数信息:

doPost detected
doGet detected
testMethod2
username: [张三]
password: [w123e21]
postParam password: w123e21
postParam username: 张三

做了两次打印的原因是第一个打印是直接调用ServletAPI实现:

基本的POST表单请求Servlet有做识别处理

    public static void printAllParamByRequestMap(HttpServletRequest request) {
        Map<String, String[]> parameterMap = request.getParameterMap();
        for (String s : parameterMap.keySet()) {
            System.out.println(s + ": " + Arrays.toString(parameterMap.get(s)));
        }
    }

第二次打印是从输入流中获取识别的

    /**
     * 从POST请求中获取参数
     * @param request
     * @return
     * @throws Exception
     */
    public static Map<String, Object> getPostParam(HttpServletRequest request) throws Exception {
        // 返回参数
        Map<String, Object> params = new HashMap<>();

        // 获取内容格式
        String contentType = request.getContentType();

        if (null == contentType || "".equals(contentType)) throw new ServletException("没有设置请求头项Content-Type!!!");
        else contentType = contentType.split(";")[0];

        // form表单格式  表单形式可以从 ParameterMap中获取
        if (ServletConstants.CONTENT_TYPE_VALUE_URL_ENCODED2.equalsIgnoreCase(contentType)) {
            // 获取参数
            Map<String, String[]> parameterMap = request.getParameterMap();
            if (parameterMap != null) {
                for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
                    params.put(entry.getKey(), entry.getValue()[0]);
                }
            }
        }

        // json格式 json格式需要从request的输入流中解析获取
        if (ServletConstants.CONTENT_TYPE_VALUE_JSON2.equalsIgnoreCase(contentType)) {
            // 使用 commons-io中 IOUtils 类快速获取输入流内容
            String paramJson = IOUtils.toString(request.getInputStream(), StandardCharsets.UTF_8);
            Map parseObject = JSON.parseObject(paramJson, Map.class);
            params.putAll(parseObject);
        }

        return params ;
    }

 

也可以不使用  UrlEncodedFormEntity  ,使用请求头设置即可

这个意思在视频里说错了,应该是这个Entity已经在Header这么处理了

        // 配置Http请求头
        httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");

因为表单的参数还是需要放到Entity里面发送过去的

 

这里特意看了下Entity的实现结构:

搜寻Entity相关的时候发现这个博客写的也很好,涉及到Cookie相关的操作

https://www.cnblogs.com/licl11092/p/9075677.html

 

POST + JSON类型案例:

SpringMVC接受Post JSON数据时要带上 @RequestBody给方法

普通Get参数则是@RequestParam

类注解为@RestController就可以不注解@RequestBody方法

在这里我使用的是封装的一套MVC,Servlet对JSON参数是不支持的,只能从输入流自行获取

 

这里JSON参数采用的是StringEntity实现存储,看了源码发现默认是text/plain类型,也允许构造器自行设置类型

    @Test
    public void postWithFormJson() throws Exception {
        CloseableHttpClient closeableHttpClient = HttpClients.createDefault();
        java.lang.String target = "http://localhost:8080/mvc-framework/test/testMethod2";

        // 首先创建POST请求对象
        HttpPost httpPost = new HttpPost(target);

        // 设置需要提交的JSON参数 这里做简单案例,就不去下载Fastjson来转换了,自己手写一个
        String jsonParam = "{ \"username\": \"张三\", \"password\": \"w123e21\" }";

// 表单类型实体对象 装填参数信息 application/x-www-form-urlencoded
        StringEntity jsonEntity = new StringEntity(jsonParam , Consts.UTF_8);

        // 配置Http请求头
        // httpPost.addHeader("Content-Type", "application/json; charset=UTF-8");
        jsonEntity.setContentType(new BasicHeader("Content-Type", "application/json; charset=UTF-8"));
        // StringEntity 设置编码
        jsonEntity.setContentEncoding(Consts.UTF_8.name());

        // 设置JSON实体对象
        httpPost.setEntity(jsonEntity);

        // 客户端执行请求发送
        CloseableHttpResponse closeableHttpResponse = closeableHttpClient.execute(httpPost);
        HttpEntity httpEntity = closeableHttpResponse.getEntity();
        System.out.println(EntityUtils.toString(httpEntity, StandardCharsets.UTF_8));

        EntityUtils.consume(httpEntity);
        closeableHttpResponse.close();
        closeableHttpClient.close();
    }

 

POST + 文件类型案例:

 

首先测试Html表单上传文件处理:

 

上传操作的页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h3>静态资源访问 3333</h3>
    <form action="http://localhost:8080/mvc-framework/test/fileUploadTest" enctype="multipart/form-data" method="post">
        <p><label >上传文件</label> <input type="file" name="upload" ></p>
        <p><label >用户名</label> <input type="text" name="username"></p>
        <input type="submit" value="提交">
    </form>
</body>
</html>

Servlet后台:

    /**
     * POST数据处理
     * http://localhost:8080/mvc-framework/test/fileUploadTest
     * @return
     */
    @RequestMapping(value = "/fileUploadTest", methodType = MethodType.POST)
    public Map<String, Object> fileUploadTest(HttpServletRequest request) throws ServletException, IOException {

        String contentType = request.getContentType();
        // request.setCharacterEncoding("UTF-8");  注意中文乱码
        if (null == contentType || "".equals(contentType)) throw new ServletException("ContentType类型未声明!");
        System.out.println(contentType);
        if (!contentType.contains("multipart/form-data")) throw new ServletException("ContentType类型不符合文件上传的要求!");

        //获取上传的文件集合(应该是所有表单数据封装成的part对象集合)
        Collection<Part> parts = request.getParts();
        if(null == parts) throw new ServletException("没有需要上传的文件!");
        for (Part part : parts) {

            //Servlet3没有提供直接获取文件名的方法,需要从请求头中解析出来
            //获取请求头,请求头的格式:form-data; name="file"; filename="snmp4j--api.zip"
            String header = part.getHeader("content-disposition");

            // 注意这个part只有文件才会有 filename属性
            if (!header.contains("filename")) continue;

            /**
             * 每个浏览器的输出情况
             * Edge -> form-data; name="upload"; filename="QQ截图20210817220501.png"
             * 360极速 -> form-data; name="upload"; filename="C:\Users\Administrator\Pictures\QQ截图20210820005513.png"
             * 火狐 -> form-data; name="upload"; filename="QQ截图20210817220501.png"
             * 谷歌 -> form-data; name="upload"; filename="QQ截图20210817220501.png"
             * IE -> form-data; name="upload"; filename="C:\Users\Administrator\Pictures\QQ截图20210817220501.png"
             */

            // 取得文件名称与后缀信息
            String[] nameWithSuffix = ServletUtil.getFileNameWithSuffix(header);

            // 获取本地位置:
            String savePath = request.getServletContext().getRealPath("/WEB-INF/upload");
            System.out.println(savePath);

            // 如果这个路径没有就创建一个出来
            File storagePosition = new File(savePath);
            if (!storagePosition.exists())  storagePosition.mkdirs();  // mkdirs 允许创建多层级目录

            // 输出写入到本地
            part.write(savePath + File.separator + nameWithSuffix[0]);
        }

        Map<String, Object> res = new HashMap<>();
        res.put("status", 200);
        res.put("msg", "OK");
        res.put("data", "文件上传成功!!!");
        return res;
    }

注意,这里我发现原来是没有使用Servlet3.0提供的内容来解决文件上传下载的

用的ApacheCommonsIO + FileUpload

后来才知道3.0已经提供文件上传的一些功能:

 

@MultipartConfig注解,注解在你需要做文件上传的Servlet类上面

package javax.servlet.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MultipartConfig {
    String location() default "";

    long maxFileSize() default -1L;

    long maxRequestSize() default -1L;

    int fileSizeThreshold() default 0;
}

当你想从Servlet获取上传的文件,但是没有声明此注解

Tomcat会报错:

由于没有提供multi-part配置,无法处理parts

类同SpringMVC一样

 

由于我是封装的MVC框架,所有Servlet处理的后台在DispatchServlet中调用

所以对他配置注解:

@MultipartConfig
public class DispatchServlet extends HttpServlet {

    // private Class<?> thisClass = this.getClass();

    private static Mapping currentMapping;
    private static Map<String, Mapping> allRequestMapping;
    public static final String REDIRECT = "redirect:";
    public static String dispatchPath = "/WEB-INF/jsp/";
    public static String fileSuffix = ".jsp";

下面是后台逻辑:

    /**
     * POST数据处理
     * http://localhost:8080/mvc-framework/test/fileUploadTest
     * @return
     */
    @RequestMapping(value = "/fileUploadTest", methodType = MethodType.POST)
    public Map<String, Object> fileUploadTest(HttpServletRequest request) throws ServletException, IOException {

        String contentType = request.getContentType();
        // request.setCharacterEncoding("UTF-8");  注意中文乱码
        if (null == contentType || "".equals(contentType)) throw new ServletException("ContentType类型未声明!");
        System.out.println(contentType);
        if (!contentType.contains("multipart/form-data")) throw new ServletException("ContentType类型不符合文件上传的要求!");

        //获取上传的文件集合(应该是所有表单数据封装成的part对象集合)
        Collection<Part> parts = request.getParts();
        if(null == parts) throw new ServletException("没有需要上传的文件!");
        for (Part part : parts) {

            //Servlet3没有提供直接获取文件名的方法,需要从请求头中解析出来
            //获取请求头,请求头的格式:form-data; name="file"; filename="snmp4j--api.zip"
            String header = part.getHeader("content-disposition");

            // 注意这个part只有文件才会有 filename属性
            if (!header.contains("filename")) continue;

            /**
             * 每个浏览器的输出情况
             * Edge -> form-data; name="upload"; filename="QQ截图20210817220501.png"
             * 360极速 -> form-data; name="upload"; filename="C:\Users\Administrator\Pictures\QQ截图20210820005513.png"
             * 火狐 -> form-data; name="upload"; filename="QQ截图20210817220501.png"
             * 谷歌 -> form-data; name="upload"; filename="QQ截图20210817220501.png"
             * IE -> form-data; name="upload"; filename="C:\Users\Administrator\Pictures\QQ截图20210817220501.png"
             */

            // 取得文件名称与后缀信息
            String[] nameWithSuffix = ServletUtil.getFileNameWithSuffix(header);

            // 获取本地位置:
            String savePath = request.getServletContext().getRealPath("/WEB-INF/upload");
            System.out.println(savePath);

            // 如果这个路径没有就创建一个出来
            File storagePosition = new File(savePath);
            if (!storagePosition.exists())  storagePosition.mkdirs();  // mkdirs 允许创建多层级目录

            // 输出写入到本地
            part.write(savePath + File.separator + nameWithSuffix[0]);
        }

        Map<String, Object> res = new HashMap<>();
        res.put("status", 200);
        res.put("msg", "OK");
        res.put("data", "文件上传成功!!!");
        return res;
    }

这个功能比之前的Apache封装要简单多了

直接可以输出写入到本地

 

追加上获取文件名的办法:

    public static String[] getFileNameWithSuffix(String partHeader) throws ServletException {
        String[] fileNameArr = new String[2];
        if(!partHeader.contains("filename")) throw new ServletException("找不到文件名称");
        String filename = partHeader.split("filename")[1];

        filename = filename.replace("=", "");
        filename = filename.replace("\"", "");
        if (filename.contains("\\")) { // 例如IE的情况,带有绝对路径信息
            filename = filename.substring(filename.lastIndexOf("\\"));
        }
        fileNameArr[0] = filename;
        fileNameArr[1] = filename.substring(filename.lastIndexOf("."));
        return fileNameArr;
    }

视频里面用的IE浏览器,可以抓到这个Content-Disposition 信息

 但是我用Edge是看不到的

 同样用IE看也没有。。。

 

使用HttpClient实现文件上传:

需要新增一个MIME依赖:

        <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpmime -->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpmime</artifactId>
            <version>4.5.13</version>
        </dependency>

 

客户端代码:

    @Test
    public void postWithFormMultiPart() throws Exception {
        CloseableHttpClient closeableHttpClient = HttpClients.createDefault();
        java.lang.String target = "http://localhost:8080/mvc-framework/test/fileUploadTest";

        // 首先创建POST请求对象
        HttpPost httpPost = new HttpPost(target);

        // 创建文件上传实体对象
        MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();

        HttpEntity httpEntity = multipartEntityBuilder
                // 设置ContentType 类型
                .setContentType(ContentType.MULTIPART_FORM_DATA)
                // 设置编码,编码重置
                .setCharset(Consts.UTF_8)
                // 设置模式(浏览器模式)
                .setMode(HttpMultipartMode.BROWSER_COMPATIBLE)
                // 添加附件
                .addBinaryBody("project-repo.txt", new File("C:\\Users\\Administrator\\Desktop\\project-repo.txt"))
                // 添加part附件
                .addPart("partFile", new FileBody(new File("C:\\Users\\Administrator\\Pictures\\QQplayerPic\\4[00_00_50][20210919-092125].png")))
                // 添加文本附件 但是文本附件不会被上传到服务器里面 原因可能是不具备filename
                .addTextBody("txtBody1", "张三")
                .addTextBody("txtBody2", "1qwdasx")
                .build();
// 设置文件上传实体对象
        httpPost.setEntity(httpEntity);

        // 客户端执行请求发送
        CloseableHttpResponse closeableHttpResponse = closeableHttpClient.execute(httpPost);
        httpEntity = closeableHttpResponse.getEntity();
        System.out.println(EntityUtils.toString(httpEntity, StandardCharsets.UTF_8));

        EntityUtils.consume(httpEntity);
        closeableHttpResponse.close();
        closeableHttpClient.close();
    }

关于addPart下面一个重载方法:

 

客户端响应:

{"msg":"OK","data":"文件上传成功!!!","status":200}

服务器只触发了两次:

说明下面的两个textBody是不识别的,因为我设置了方法

doPost detected
doGet detected
multipart/form-data; boundary=0Oz1eCUwv_bwYAEDfOi5K-s4DshztEqsLWsW5; charset=UTF-8
C:\Users\Administrator\IdeaProjects\MVC-Framework\out\artifacts\MVC_Framwork\WEB-INF\upload
C:\Users\Administrator\IdeaProjects\MVC-Framework\out\artifacts\MVC_Framwork\WEB-INF\upload

我放开打印再看看结果:

可以看到文本体就是没有filename的存在

form-data; name="project-repo.txt"; filename="project-repo.txt"
C:\Users\Administrator\IdeaProjects\MVC-Framework\out\artifacts\MVC_Framwork\WEB-INF\upload
form-data; name="partFile"; filename="4[00_00_50][20210919-092125].png"
C:\Users\Administrator\IdeaProjects\MVC-Framework\out\artifacts\MVC_Framwork\WEB-INF\upload
form-data; name="txtBody1"
form-data; name="txtBody2"

也就是textBody相当于input标签,设置类型type="text"了

 

这里存在一个中文乱码的问题,并不是过滤器能够解决的了

txtBody1: [??]
txtBody2: [1qwdasx]

客户端发送就会乱码

因为建造器不支持对应的中文字符

// 添加文本附件 但是文本附件不会被上传到服务器里面 原因可能是不具备filename
.addTextBody("txtBody1", "张三")
.addTextBody("txtBody2", "1qwdasx")

需要这样编写:

// 添加文本附件 但是文本附件不会被上传到服务器里面 原因可能是不具备filename
.addPart("txtBody1", new StringBody("张三", ContentType.create("text/plain", Consts.UTF_8)))
.addTextBody("txtBody2", "1qwdasx")

再打印就正常了:

doPost detected
doGet detected
txtBody1: [张三]
txtBody2: [1qwdasx]
multipart/form-data; boundary=VBLteRGDXG2JWQyo3e3o7Ez8Wzzzb-u4fOURku0; charset=UTF-8
form-data; name="project-repo.txt"; filename="project-repo.txt"
C:\Users\Administrator\IdeaProjects\MVC-Framework\out\artifacts\MVC_Framwork\WEB-INF\upload
form-data; name="partFile"; filename="4[00_00_50][20210919-092125].png"
C:\Users\Administrator\IdeaProjects\MVC-Framework\out\artifacts\MVC_Framwork\WEB-INF\upload
form-data; name="txtBody1"
form-data; name="txtBody2"

 

 

7、HTTPS安全认证越过:

这里借用JSON的那个请求测试

唯一的区别是请求地址追加了s,使用HTTPS认证

然后客户端请求就会报错

    @Test
    public void sslCross() throws Exception {
        CloseableHttpClient closeableHttpClient = HttpClients.createDefault();
        java.lang.String target = "https://localhost:8080/mvc-framework/test/testMethod2";

        // 首先创建POST请求对象
        HttpPost httpPost = new HttpPost(target);

        // 设置需要提交的JSON参数 这里做简单案例,就不去下载Fastjson来转换了,自己手写一个
        String jsonParam = "{ \"username\": \"张三\", \"password\": \"w123e21\" }";

        // 表单类型实体对象 装填参数信息 application/x-www-form-urlencoded
        StringEntity jsonEntity = new StringEntity(jsonParam , Consts.UTF_8);

        // 配置Http请求头
        // httpPost.addHeader("Content-Type", "application/json; charset=UTF-8");
        jsonEntity.setContentType(new BasicHeader("Content-Type", "application/json; charset=UTF-8"));
        // StringEntity 设置编码
        jsonEntity.setContentEncoding(Consts.UTF_8.name());

        // 设置JSON实体对象
        httpPost.setEntity(jsonEntity);

        // 客户端执行请求发送
        CloseableHttpResponse closeableHttpResponse = closeableHttpClient.execute(httpPost);
        HttpEntity httpEntity = closeableHttpResponse.getEntity();
        System.out.println(EntityUtils.toString(httpEntity, StandardCharsets.UTF_8));

        EntityUtils.consume(httpEntity);
        closeableHttpResponse.close();
        closeableHttpClient.close();
    }

报错信息:

"C:\Program Files (x86)\Java\jdk1.8.0_291\bin\java.exe" -ea -Didea.test.cyclic.buffer.size=1048576 "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2021.2.1\lib\idea_rt.jar=60373:C:\Program Files\JetBrains\IntelliJ IDEA 2021.2.1\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\JetBrains\IntelliJ IDEA 2021.2.1\lib\idea_rt.jar;C:\Program Files\JetBrains\IntelliJ IDEA 2021.2.1\plugins\junit\lib\junit5-rt.jar;C:\Program Files\JetBrains\IntelliJ IDEA 2021.2.1\plugins\junit\lib\junit-rt.jar;C:\Program Files (x86)\Java\jdk1.8.0_291\jre\lib\charsets.jar;C:\Program Files (x86)\Java\jdk1.8.0_291\jre\lib\deploy.jar;C:\Program Files (x86)\Java\jdk1.8.0_291\jre\lib\ext\access-bridge-32.jar;C:\Program Files (x86)\Java\jdk1.8.0_291\jre\lib\ext\cldrdata.jar;C:\Program Files (x86)\Java\jdk1.8.0_291\jre\lib\ext\dnsns.jar;C:\Program Files (x86)\Java\jdk1.8.0_291\jre\lib\ext\jaccess.jar;C:\Program Files (x86)\Java\jdk1.8.0_291\jre\lib\ext\jfxrt.jar;C:\Program Files (x86)\Java\jdk1.8.0_291\jre\lib\ext\localedata.jar;C:\Program Files (x86)\Java\jdk1.8.0_291\jre\lib\ext\nashorn.jar;C:\Program Files (x86)\Java\jdk1.8.0_291\jre\lib\ext\sunec.jar;C:\Program Files (x86)\Java\jdk1.8.0_291\jre\lib\ext\sunjce_provider.jar;C:\Program Files (x86)\Java\jdk1.8.0_291\jre\lib\ext\sunmscapi.jar;C:\Program Files (x86)\Java\jdk1.8.0_291\jre\lib\ext\sunpkcs11.jar;C:\Program Files (x86)\Java\jdk1.8.0_291\jre\lib\ext\zipfs.jar;C:\Program Files (x86)\Java\jdk1.8.0_291\jre\lib\javaws.jar;C:\Program Files (x86)\Java\jdk1.8.0_291\jre\lib\jce.jar;C:\Program Files (x86)\Java\jdk1.8.0_291\jre\lib\jfr.jar;C:\Program Files (x86)\Java\jdk1.8.0_291\jre\lib\jfxswt.jar;C:\Program Files (x86)\Java\jdk1.8.0_291\jre\lib\jsse.jar;C:\Program Files (x86)\Java\jdk1.8.0_291\jre\lib\management-agent.jar;C:\Program Files (x86)\Java\jdk1.8.0_291\jre\lib\plugin.jar;C:\Program Files (x86)\Java\jdk1.8.0_291\jre\lib\resources.jar;C:\Program Files (x86)\Java\jdk1.8.0_291\jre\lib\rt.jar;C:\Users\Administrator\IdeaProjects\Anything\Framework\target\test-classes;C:\Users\Administrator\IdeaProjects\Anything\Framework\target\classes;C:\Users\Administrator\.m2\repository\org\apache\httpcomponents\httpclient\4.5.13\httpclient-4.5.13.jar;C:\Users\Administrator\.m2\repository\org\apache\httpcomponents\httpcore\4.4.12\httpcore-4.4.12.jar;C:\Users\Administrator\.m2\repository\commons-logging\commons-logging\1.2\commons-logging-1.2.jar;C:\Users\Administrator\.m2\repository\commons-codec\commons-codec\1.13\commons-codec-1.13.jar;C:\Users\Administrator\.m2\repository\org\apache\httpcomponents\httpmime\4.5.13\httpmime-4.5.13.jar;C:\Users\Administrator\.m2\repository\javax\servlet\javax.servlet-api\4.0.1\javax.servlet-api-4.0.1.jar;C:\Users\Administrator\.m2\repository\javax\servlet\jstl\1.2\jstl-1.2.jar;C:\Users\Administrator\.m2\repository\javax\servlet\jsp\javax.servlet.jsp-api\2.3.3\javax.servlet.jsp-api-2.3.3.jar;C:\Users\Administrator\.m2\repository\org\reflections\reflections\0.9.11\reflections-0.9.11.jar;C:\Users\Administrator\.m2\repository\com\google\guava\guava\20.0\guava-20.0.jar;C:\Users\Administrator\.m2\repository\junit\junit\4.12\junit-4.12.jar;C:\Users\Administrator\.m2\repository\org\hamcrest\hamcrest-core\2.1\hamcrest-core-2.1.jar;C:\Users\Administrator\.m2\repository\org\hamcrest\hamcrest\2.1\hamcrest-2.1.jar;C:\Users\Administrator\.m2\repository\commons-io\commons-io\2.11.0\commons-io-2.11.0.jar;C:\Users\Administrator\.m2\repository\commons-beanutils\commons-beanutils\1.7.0\commons-beanutils-1.7.0.jar;C:\Users\Administrator\.m2\repository\org\javassist\javassist\3.26.0-GA\javassist-3.26.0-GA.jar;C:\Users\Administrator\.m2\repository\com\alibaba\fastjson\1.2.78\fastjson-1.2.78.jar" com.intellij.rt.junit.JUnitStarter -ideVersion5 -junit4 HttpClientTest,sslCross

javax.net.ssl.SSLException: Unsupported or unrecognized SSL message

    at sun.security.ssl.SSLSocketInputRecord.handleUnknownRecord(SSLSocketInputRecord.java:448)
    at sun.security.ssl.SSLSocketInputRecord.decode(SSLSocketInputRecord.java:174)
    at sun.security.ssl.SSLTransport.decode(SSLTransport.java:110)
    at sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1290)
    at sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1199)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:401)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:373)
    at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:436)
    at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:384)
    at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:142)
    at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:376)
    at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:393)
    at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236)
    at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:186)
    at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
    at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
    at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:108)
    at HttpClientTest.sslCross(HttpClientTest.java:348)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
    at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
    at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
    at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)


Process finished with exit code -1

同样服务器也报错:

05-Oct-2021 14:40:01.846 信息 [http-nio-8080-exec-6] org.apache.coyote.http11.Http11Processor.service 解析 HTTP 请求 header 错误
 注意:HTTP请求解析错误的进一步发生将记录在DEBUG级别。
    java.lang.IllegalArgumentException: 在方法名称中发现无效的字符串, HTTP 方法名必须是有效的符号.
        at org.apache.coyote.http11.Http11InputBuffer.parseRequestLine(Http11InputBuffer.java:434)
        at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:511)
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:831)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1650)
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
        at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
        at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.lang.Thread.run(Thread.java:748)

这里没证书,一笔带过了,直接上代码:

主要是对客户端设置相关的SSL机制,其余的都是一样使用

    @Test
    public void sslCross() throws Exception {

        SSLContextBuilder sslContextBuilder = new SSLContextBuilder();

        sslContextBuilder.loadTrustMaterial(null, new TrustStrategy() {
            @Override
            public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
                return true;
            }
        });

        SSLContext sslContext = sslContextBuilder.build();

        SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
                sslContext,
                new String[]{
                        "SSLv2Hello",
                        "SSLv3",
                        "TLSv1",
                        "TLSv1.1",
                        "TLSv1.2"
                },
                null,
                NoopHostnameVerifier.INSTANCE
        );
        
        Registry<ConnectionSocketFactory> registry = RegistryBuilder
                .<ConnectionSocketFactory>create()
                .register("http", PlainConnectionSocketFactory.INSTANCE)
                .register("https", sslConnectionSocketFactory)
                .build();
        
        PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(registry);

        // 客户端对象需要定制化
        HttpClientBuilder httpClientBuilder = HttpClients.custom().setConnectionManager(poolingHttpClientConnectionManager);

        CloseableHttpClient closeableHttpClient = httpClientBuilder.build();

        java.lang.String target = "https://localhost:8080/mvc-framework/test/testMethod2";

        // 首先创建POST请求对象
        HttpPost httpPost = new HttpPost(target);

        // 设置需要提交的JSON参数 这里做简单案例,就不去下载Fastjson来转换了,自己手写一个
        String jsonParam = "{ \"username\": \"张三\", \"password\": \"w123e21\" }";

        // 表单类型实体对象 装填参数信息 application/x-www-form-urlencoded
        StringEntity jsonEntity = new StringEntity(jsonParam , Consts.UTF_8);

        // 配置Http请求头
        // httpPost.addHeader("Content-Type", "application/json; charset=UTF-8");
        jsonEntity.setContentType(new BasicHeader("Content-Type", "application/json; charset=UTF-8"));
        // StringEntity 设置编码
        jsonEntity.setContentEncoding(Consts.UTF_8.name());

        // 设置JSON实体对象
        httpPost.setEntity(jsonEntity);

        // 客户端执行请求发送
        CloseableHttpResponse closeableHttpResponse = closeableHttpClient.execute(httpPost);
        HttpEntity httpEntity = closeableHttpResponse.getEntity();
        System.out.println(EntityUtils.toString(httpEntity, StandardCharsets.UTF_8));

        EntityUtils.consume(httpEntity);
        closeableHttpResponse.close();
        closeableHttpClient.close();
    }

 

8、连接池与工具封装

 

package cn.dzz.framework.util;

import org.apache.http.*;
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.methods.HttpPost;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeader;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.TrustStrategy;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLContext;
import javax.servlet.ServletException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class HttpClientUtil {


    private static final HttpClientBuilder httpClientBuilder = HttpClients.custom();

    static {
        try {
            // 连接管理器
            SSLContextBuilder sslContextBuilder = new SSLContextBuilder();
            sslContextBuilder.loadTrustMaterial(null, new TrustStrategy() {
                @Override
                public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
                    return true;
                }
            });

            SSLContext sslContext = sslContextBuilder.build();

            SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
                    sslContext,
                    new String[]{
                            "SSLv2Hello",
                            "SSLv3",
                            "TLSv1",
                            "TLSv1.1",
                            "TLSv1.2"
                    },
                    null,
                    NoopHostnameVerifier.INSTANCE
            );

            Registry<ConnectionSocketFactory> registry = RegistryBuilder
                    .<ConnectionSocketFactory>create()
                    .register("http", PlainConnectionSocketFactory.INSTANCE)
                    .register("https", sslConnectionSocketFactory)
                    .build();

            PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(registry);
            poolingHttpClientConnectionManager.setMaxTotal(50);// 连接池最大连接数量
            poolingHttpClientConnectionManager.setDefaultMaxPerRoute(50); // 每个路由的默认连接 路由 = ip + port

            httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager);

            // 请求默认配置
            RequestConfig requestConfig = RequestConfig
                    .custom()
                    .setConnectTimeout(6000)
                    .setSocketTimeout(3000)
                    .setConnectionRequestTimeout(6000)
                    .build();
            httpClientBuilder.setDefaultRequestConfig(requestConfig);

            // 默认请求头配置
            List<Header> headerList = new ArrayList<>();
            BasicHeader agentHeader = new BasicHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36 Edg/94.0.992.38");

            headerList.add(agentHeader);
            httpClientBuilder.setDefaultHeaders(headerList);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 发送GET请求
     * @param url
     * @param headers
     * @return
     */
    public static String executeGetRequest(String url, Map<String, String> headers) {
        CloseableHttpClient closeableHttpClient = null;
        CloseableHttpResponse closeableHttpResponse = null;
        HttpEntity httpEntity = null;
        String resJson = null;
        try {
            closeableHttpClient = httpClientBuilder.build();

            // 配置请求地址
            HttpGet httpGet = new HttpGet(url);

            // 配置请求头信息
            for (String key : headers.keySet()) httpGet.addHeader(key, headers.get(key));

            // 请求发送
            closeableHttpResponse = closeableHttpClient.execute(httpGet);

            // 状态判定
            StatusLine statusLine = closeableHttpResponse.getStatusLine();
            int statusCode = statusLine.getStatusCode();
            if ( ! isSuccessRequest(statusCode)) throw new ServletException(url + " 请求失败, " + statusLine);

            httpEntity = closeableHttpResponse.getEntity();
            resJson = EntityUtils.toString(httpEntity);
        } catch (Exception exception) {
            exception.printStackTrace();
            return null;
        } finally {
            try {
                EntityUtils.consume(httpEntity);
                closeableHttpResponse.close();
                closeableHttpClient.close();
            } catch (Exception exception) {
                exception.printStackTrace();
            }
        }
        return resJson;
    }

    /**
     * 发送POST请求
     * @param url
     * @param headers
     * @return
     */
    public static String executeGetRequest(String url, String json, Map<String, String> headers) {
        CloseableHttpClient closeableHttpClient = null;
        CloseableHttpResponse closeableHttpResponse = null;
        HttpEntity httpEntity = null;
        String resJson = null;
        try {
            closeableHttpClient = httpClientBuilder.build();

            // 配置请求地址
            HttpPost httpPost = new HttpPost(url);

            // 配置请求头信息
            for (String key : headers.keySet()) httpPost.addHeader(key, headers.get(key));
            httpPost.addHeader("Content-Type", "application/json; charset=UTF-8");

            // 请求体设置
            StringEntity jsonEntity = new StringEntity(json, Consts.UTF_8);
            jsonEntity.setContentEncoding(Consts.UTF_8.name());
            jsonEntity.setContentType("application/json; charset=UTF-8");
            httpPost.setEntity(jsonEntity);

            // 请求发送
            closeableHttpResponse = closeableHttpClient.execute(httpPost);

            // 状态判定
            StatusLine statusLine = closeableHttpResponse.getStatusLine();
            int statusCode = statusLine.getStatusCode();
            if ( ! isSuccessRequest(statusCode)) throw new ServletException(url + " 请求失败, " + statusLine);

            httpEntity = closeableHttpResponse.getEntity();
            resJson = EntityUtils.toString(httpEntity);
        } catch (Exception exception) {
            exception.printStackTrace();
            return null;
        } finally {
            try {
                EntityUtils.consume(httpEntity);
                closeableHttpResponse.close();
                closeableHttpClient.close();
            } catch (Exception exception) {
                exception.printStackTrace();
            }
        }
        return resJson;
    }


    /**
     * 这里判定条件宽泛,只要是2和3都算请求成功
     * @param statusCode
     * @return
     */
    public static boolean isSuccessRequest(int statusCode) {
        boolean flag = false;
        switch (statusCode) {
                // 2XX状态
            case HttpStatus.SC_OK:
            case HttpStatus.SC_CREATED:
            case HttpStatus.SC_ACCEPTED:
            case HttpStatus.SC_NON_AUTHORITATIVE_INFORMATION:
            case HttpStatus.SC_NO_CONTENT:
            case HttpStatus.SC_RESET_CONTENT:
            case HttpStatus.SC_PARTIAL_CONTENT:
            case HttpStatus.SC_MULTI_STATUS:
            case HttpStatus.SC_MULTIPLE_CHOICES:
                // 3XX状态
            case HttpStatus.SC_MOVED_PERMANENTLY:
            case HttpStatus.SC_MOVED_TEMPORARILY:
            case HttpStatus.SC_SEE_OTHER:
            case HttpStatus.SC_NOT_MODIFIED:
            case HttpStatus.SC_USE_PROXY:
            case HttpStatus.SC_TEMPORARY_REDIRECT:
                flag = true;
                break;
            default:
        }
        return flag;
    }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2021-10-05 10:45  emdzz  阅读(265)  评论(0编辑  收藏  举报