用5种方式发起HTTP请求

发布时间 2023-11-25 14:41:49作者: 残城碎梦

通过JDK网络类Java.net.HttpURLConnection

<!--jackson-->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.12.4</version>
</dependency>

比较原始的一种调用做法。

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import com.fasterxml.jackson.databind.ObjectMapper;

public final class ConnectUtil {

    private static ObjectMapper objectMapper = new ObjectMapper();

    private ConnectUtil() {
    }

    public <T, R> R doPost(String httpUrl, T params, Class<R> returnType, String token) throws IOException {
        StringBuilder result = new StringBuilder();
        //连接
        HttpURLConnection connection = null;
        OutputStream os = null;
        InputStream is = null;
        BufferedReader br = null;
        try {
            //创建连接对象
            URL url = new URL(httpUrl);
            //创建连接
            connection = (HttpURLConnection) url.openConnection();
            //设置请求方法
            connection.setRequestMethod("POST");
            //设置连接超时时间(必须)
            connection.setConnectTimeout(15000);
            //设置读取超时时间(必须)
            connection.setReadTimeout(15000);
            //DoOutput设置是否向httpUrlConnection输出,DoInput设置是否从httpUrlConnection读入,此外发送post请求必须设置这两个
            //设置是否可读取
            connection.setDoOutput(true);
            connection.setDoInput(true);
            //设置通用的请求属性
            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)");
            connection.setRequestProperty("Content-Type", "application/json;charset=utf-8");
            //(可选)设置请求头鉴权信息
            if (token != null && !"".equals(token)) {
                connection.addRequestProperty("Authorization", token);
            }

            // 建立实际的连接
            connection.connect();
            //拼装参数
            if (null != params) {
                String param = objectMapper.writeValueAsString(params);
                //设置参数
                os = connection.getOutputStream();
                OutputStreamWriter writer = new OutputStreamWriter(os, "UTF-8");
                //拼装参数
                writer.write(param);
                writer.flush();

                //另一种方式
                //设置参数
                //os = connection.getOutputStream();
                //拼装参数
                //os.write(param.getBytes("UTF-8"));
            }
            //设置权限
            //设置请求头等
            //开启连接
            //connection.connect();
            //读取响应
            if (connection.getResponseCode() == 200) {
                is = connection.getInputStream();
                if (null != is) {
                    br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
                    String temp = null;
                    while (null != (temp = br.readLine())) {
                        result.append(temp);
                        result.append("\r\n");
                    }
                }
            }

        } finally {
            //关闭连接
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            //关闭连接
            connection.disconnect();
        }
        R object = objectMapper.readValue(result.toString(), returnType);
        return object;
    }

    /**
     * Http get请求
     *
     * @param httpUrl 连接
     * @return 响应数据
     */
    public static String doGet(String httpUrl, String param, String token) {
        //链接
        HttpURLConnection connection = null;
        InputStream is = null;
        BufferedReader br = null;
        StringBuffer result = new StringBuffer();
        try {
            //创建连接
            if (param != null && !"".equals(param)) {
                httpUrl = httpUrl + "?" + param;
            }
            URL url = new URL(httpUrl);
            connection = (HttpURLConnection) url.openConnection();
            //设置请求方式
            connection.setRequestMethod("GET");
            //设置连接超时时间
            connection.setReadTimeout(15000);
            //(可选)设置请求头鉴权信息
            if (token != null && !"".equals(token)) {
                connection.addRequestProperty("Authorization", token);
            }

            //开始连接
            connection.connect();

            //请求参数(这里不要把参数放到outputStream中,会自动变成post请求)
            /*  if (param != null && !"".equals(param)) {
                OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream(), "UTF-8");
                writer.write(param);
                writer.flush();
            }*/

            //获取响应数据
            if (connection.getResponseCode() == 200) {
                //获取返回的数据
                is = connection.getInputStream();
                if (null != is) {
                    br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
                    String temp = null;
                    while (null != (temp = br.readLine())) {
                        result.append(temp);
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (null != br) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != is) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            //关闭远程连接
            connection.disconnect();
        }
        return result.toString();
    }
}

通过Apache Common封装好的HttpClient请求

<dependency>
    <groupId>commons-httpclient</groupId>
    <artifactId>commons-httpclient</artifactId>
    <version>3.1</version>
</dependency>

<!--jackson-->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.12.4</version>
</dependency>
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.commons.httpclient.params.HttpConnectionParams;
import org.apache.commons.httpclient.params.HttpMethodParams;

import java.io.IOException;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

public final class HttpUtil {
    private static ObjectMapper objectMapper = new ObjectMapper();
    private static HttpClient httpClient = new HttpClient();

    private HttpUtil() {
    }

    static {
        objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
        //1.设置HttpClient参数
        //连接超时时间
        httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(5000);
        //读写超时时间
        httpClient.getParams().setParameter(HttpConnectionParams.SO_TIMEOUT, 5000);
    }

    /**
     * @param url
     * @param param 这里使用泛型和Object都是一样的,不影响
     * @return
     * @throws IOException
     * @throws IllegalAccessException
     */
    public static String doGet(String url, Object param, String token) throws IOException, IllegalAccessException {
        //2.生成GetMethod对象并设置参数
        if (Objects.nonNull(param)) {
            List<String> params = new ArrayList<>();
            Class<?> clazz = param.getClass();
            Field[] declaredFields = clazz.getDeclaredFields();
            for (Field declaredField : declaredFields) {
                declaredField.setAccessible(true);
                Object o = declaredField.get(param);
                if (declaredField.getType().equals(String.class)) {
                    //这里拼接的时候注意要使用URL编码
                    String s = (String) declaredField.get(param);
                    s = URLEncoder.encode(s, "UTF-8");
                    o = s;
                }
                params.add(declaredField.getName() + "=" + o);
            }
            String paramStr = params.stream().collect(Collectors.joining("&"));
            url = url + "?" + paramStr;
        }
        GetMethod getMethod = new GetMethod(url);
        //设置get请求超时为5秒
        //getMethod.getParams().setParameter(HttpMethodParams.SO_TIMEOUT, 5000);
        //设置请求重试处理,用的是默认的重试处理:请求三次
        getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler());
        //设置请求头
        //(可选)设置请求头鉴权信息
        if (token != null && !"".equals(token)) {
            getMethod.addRequestHeader("Authorization", token);
        }
        String response = "";
        //3.执行HTTP GET 请求
        try {
            int statusCode = httpClient.executeMethod(getMethod);
            //4.判断访问的状态码
            if (statusCode != HttpStatus.SC_OK) {
                System.out.println("请求出错:" + getMethod.getStatusLine());
                return null;
            }
            //5.处理HTTP响应内容
            //HTTP响应头部信息,这里简单打印
            Header[] headers = getMethod.getResponseHeaders();
            for (Header h : headers) {
                System.out.println(h.getName() + "---------------" + h.getValue());
            }
            //读取HTTP响应内容,这里简单打印网页内容
            //读取为字节数组
            byte[] responseBody = getMethod.getResponseBody();
            response = new String(responseBody, "UTF-8");
            //读取为InputStream,在网页内容数据量大时候推荐使用
            //InputStream response = getMethod.getResponseBodyAsStream();
        } finally {
            //6.释放连接
            getMethod.releaseConnection();
        }
        return response;
    }

    public static <R> R doPost(String httpUrl, Object param, Class<R> returnType) throws IOException {
        String json = "";
        if (Objects.nonNull(param)) {
            json = objectMapper.writeValueAsString(param);
        }

        PostMethod postMethod = new PostMethod(httpUrl);
        //postMethod.getParams().setParameter(HttpMethodParams.SO_TIMEOUT, 5000);

        //这里accept表示的是可接收的返回值类型,一般设置为*/*
        //如果不设置将会使用浏览器的默认值,不过一般都会支持*/*,为了保险还是加上吧
        //如果返回值类型不匹配则会提示No content to map due to end-of-input,可以尝试设置text/html试一下
        postMethod.addRequestHeader("accept", "*/*");

        //HTTP1.1协议默认使用Keep-Alive,如果是1.0的HTTP协议需要设置
        //Keep-Alive发送请求时性能更高
        postMethod.addRequestHeader("connection", "Keep-Alive");
        //告诉服务器请求的媒体类型,目前基本都是用json,所以设置json格式传送
        //即使不设置也是application/json,可能由于下面用到了StringRequestEntity、
        //但是我注释了下面的StringRequestEntity还是application/json,目前搞不懂,所以暂时这么设置了
        postMethod.addRequestHeader("Content-Type", "application/json;charset=UTF-8");

        //设置下面这个Header,没什么用,注释了也能正常访问
        //postMethod.addRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36");

        //添加请求参数
        RequestEntity se = new StringRequestEntity(json, "application/json", "UTF-8");
        postMethod.setRequestEntity(se);

        StringBuilder res = new StringBuilder();
        try {
            //必须要UTF-8,不然中文乱码
            //3. 执行方法
            int code = httpClient.executeMethod(postMethod);
            //4. 处理状态码
            if (code != 200) {
                System.out.println("请求出错:" + postMethod.getStatusLine());
                //这里最好是抛出一个异常
                return null;
            }
            //5. 正常,进行处理
            //方法1:拿到字节数据后使用new String
            byte[] responseBody = postMethod.getResponseBody();
            res.append(new String(responseBody, "UTF-8"));
            System.out.println(res.toString());

            //方法2:逐行读,在网页内容数据量大时候推荐使用
            /*InputStream responseStream = postMethod.getResponseBodyAsStream();
            InputStreamReader reader = new InputStreamReader(responseStream,"UTF-8");
            BufferedReader bufferedReader = new BufferedReader(reader);
            String line = null;
            while((line = bufferedReader.readLine()) !=null){
                res.append(line).append("\r\n");

            }*/
            System.out.println(res.toString());
        } finally {
            //6. 释放连接
            postMethod.releaseConnection();
        }
        R r = objectMapper.readValue(res.toString(), returnType);
        return r;

    }
}

通过Spring-RestTemplate

Spring RestTemplate 是 Spring 提供的用于访问 Rest 服务的客户端,RestTemplate 提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率。

<!--包含了RestTemplate-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>5.0.2.RELEASE</version>
</dependency>

<!--CloseableHttpClient-->
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.13</version>
</dependency>
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

import java.util.Map;

public final class RestTemplateUtil {

    private RestTemplateUtil() {
    }

    //如果是spring的web项目, 只需要注入即可,无需手动new
    //@Autowired
    // private RestTemplate restTemplate;

    private static RestTemplate restTemplate = new RestTemplate();

    static {
        HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory
                = new HttpComponentsClientHttpRequestFactory();
        //连接超时时间
        httpComponentsClientHttpRequestFactory.setConnectTimeout(10000);
        //读取超时时间
        httpComponentsClientHttpRequestFactory.setReadTimeout(10000);
        restTemplate.setRequestFactory(httpComponentsClientHttpRequestFactory);
    }

    public static String doGet(String url) {
        ResponseEntity<String> forEntity = restTemplate.getForEntity(url, String.class);
        return forEntity.getBody();
    }

    public static String doPost(String url, Map<String, Object> params) {
        ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, params, String.class);
        return responseEntity.getBody();
    }
}

通过Apache封装好的CloseableHttpClient

<!--jackson-->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.12.4</version>
</dependency>
<!--CloseableHttpClient-->
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.13</version>
</dependency>
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

public final class HttpClientUtil {

    private HttpClientUtil() {
    }

    private static ObjectMapper objectMapper = new ObjectMapper();

    private static HttpClient httpClient;

    static {
        //设置客户端,如果无参数设置可以不用调setDefaultRequestConfig方法
        RequestConfig build = RequestConfig.custom()
            .setSocketTimeout(6000)
            .setConnectTimeout(6000).build();
        httpClient = HttpClientBuilder.create().setDefaultRequestConfig(build).build();
    }

    /**
     * 以post方式调用第三方接口
     *
     * @param url
     * @param param
     * @return
     */
    public <R> R doPost(String url, Object param, Class<R> returnType, String token) throws IOException {
        String json = "";
        if (Objects.nonNull(param)) {
            json = objectMapper.writeValueAsString(param);
        }
        HttpPost httpPost = new HttpPost(url);
        if (null != token && !token.equals("")) {
            //Authorization的header头,用于token验证使用
            httpPost.addHeader("Authorization", token);
        }

        httpPost.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36");

        StringBuilder res = new StringBuilder();

        //设置编码UTF-8,不然会出现问号
        StringEntity se = new StringEntity(json, "UTF-8");
        //经过验证,无用
        //se.setContentEncoding("UTF-8");
        //发送json数据需要设置contentType,否则提供者端提示请求类型not support
        se.setContentType("application/json");
        //设置请求参数
        httpPost.setEntity(se);
        //客户端设置了默认值,局部就无需再设置,除非有额外要求
        /*RequestConfig build = RequestConfig.custom().setSocketTimeout(40000).setConnectTimeout(40000).build();
        httpPost.setConfig(build);*/

        HttpResponse response = httpClient.execute(httpPost);
        if (Objects.nonNull(response) && response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
            //返回json格式
            res.append(EntityUtils.toString(response.getEntity(), "UTF-8"));
        }
        //这里不需要手动调用httpClient.close(),因为EntityUtils.toString方法中会自动调用输入流的close方法
        //直接调用httpClient.close()反而会再第二次调用时出现Collection Pool shut down的错误
        R r = objectMapper.readValue(res.toString(), returnType);
        return r;
    }

    /**
     * 以get方式调用第三方接口
     *
     * @param url
     * @return
     */
    public static String doGet(String url, Object param, String token) throws IOException, IllegalAccessException {
        //拼接url参数
        if (Objects.nonNull(param)) {
            List<String> params = new ArrayList<>();
            Class<?> clazz = param.getClass();
            Field[] declaredFields = clazz.getDeclaredFields();
            for (Field declaredField : declaredFields) {
                declaredField.setAccessible(true);
                Object o = declaredField.get(param);
                if (declaredField.getType().equals(String.class)) {
                    //这里拼接的时候注意要使用URL编码
                    String s = (String) declaredField.get(param);
                    s = URLEncoder.encode(s);
                    o = s;
                }
                params.add(declaredField.getName() + "=" + o);
            }
            String paramStr = params.stream().collect(Collectors.joining("&"));
            url = url + "?" + paramStr;
        }


        //创建HttpClient对象
        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
        HttpGet httpGet = new HttpGet(url);
        if (null != token && !token.equals("")) {
            //api_gateway_auth_token自定义header头,用于token验证使用
            httpGet.addHeader("Authorization", token);
        }

        //httpGet.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36");
        HttpResponse response = httpClient.execute(httpGet);
        StringBuilder res = new StringBuilder();
        if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
            //返回json格式
            res.append(EntityUtils.toString(response.getEntity()));
        }
        return res.toString();
    }
}