Java常用http请求库

5 篇文章 1 订阅


常用http请求库

  1. HttpClient:apache旗下项目,代码较复杂和冗余,且需自己处理资源回收,不推荐直接使用。
  2. OKhttp:square公司开源的java版本http客户端工具。
  3. retrofit:square公司开源的基于okhttp进一步封装的retrofit工具,可以把它理解为OKhttp的加强版。用来支持通过接口的方式发起http请求。
  4. RestTemplate:Spring提供的用于访问Rest服务的客户端。RestTemplate提供了许多便捷访问远程Http服务的方法,可以较好的提高编码效率。

使用HttpClient或者RestTemplate时,一般都会自定义封装一个HttpUtil来使用。

1. HttpClient

Apache HttpClient的两个版本:

  • 3.x版本:项目名称:The Commons HttpClient。后来独立出去了,现在这个项目已经结束了它的生命周期,不再开发和维护。
  • 4.x后的版本:项目名称:Apache Httpcomponents。项目包括HttpClient和HttpCore两大模块(HttpCore:HTTP协议实现包;HttpClient:基于HttpCore的一套客户端)。

使用方法

  1. 创建HttpClient
  2. 创建http请求,如HttpGet、HttpPost
  3. 添加请求参数
  4. 添加请求设置,如超时等
  5. 使用HttpClient执行http请求
  6. 读取返回内容并释放连接

使用示例

环境依赖

spring-boot-2.2.2.RELEASE

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
</dependency>

spring-boot-2.2.2.RELEASE默认httpclient版本4.5.10。

配置类

/**
 * @author: lijiangang
 * @date: 2022-4-2 14:50
 */
@Configuration
public class HttpClientConfig {

    @Bean
    public CloseableHttpClient httpClient() {
        // 长连接保持30秒
        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(30, TimeUnit.SECONDS);
        //设置整个连接池最大连接数 根据自己的场景决定
        connectionManager.setMaxTotal(500);
        //同路由的并发数,路由是对maxTotal的细分
        connectionManager.setDefaultMaxPerRoute(500);
        RequestConfig requestConfig = RequestConfig.custom()
                //服务器返回数据(response)的时间,超过该时间抛出read timeout
                .setSocketTimeout(10000)
                //连接上服务器(握手成功)的时间,超出该时间抛出connect timeout
                .setConnectTimeout(5000)
                //从连接池中获取连接的超时时间,超过该时间未拿到可用连接,会抛出org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool
                .setConnectionRequestTimeout(500)
                .build();
        //headers
        List<Header> headers = new ArrayList<>();
        headers.add(new BasicHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.16 Safari/537.36"));
        headers.add(new BasicHeader("Accept-Encoding", "gzip,deflate"));
        headers.add(new BasicHeader("Accept-Language", "zh-CN"));
        headers.add(new BasicHeader("Connection", "Keep-Alive"));
        headers.add(new BasicHeader("Content-type", "application/json;charset=UTF-8"));

        return HttpClientBuilder.create()
                .setDefaultRequestConfig(requestConfig)
                .setConnectionManager(connectionManager)
                .setDefaultHeaders(headers)
                // 保持长连接配置,需要在头添加Keep-Alive
                .setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy())
                //重试次数,默认是3次,没有开启
                // .setRetryHandler(new DefaultHttpRequestRetryHandler(2, true))
                .build();
    }
}

自定义请求工具类

@Component
public class HttpClientUtil {

    @Autowired
    private CloseableHttpClient httpClient;

    public String get(String url) {
        CloseableHttpResponse response = null;
        BufferedReader in;
        String result = "";
        try {
            // 创建http请求,请求设置,请求参数
            HttpGet httpGet = new HttpGet(url);
            RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(30000).setConnectionRequestTimeout(30000).setSocketTimeout(30000).build();
            httpGet.setConfig(requestConfig);
            httpGet.addHeader("Content-type", "application/json; charset=utf-8");
            httpGet.setHeader("Accept", "application/json");
            // 执行http请求
            response = httpClient.execute(httpGet);
            in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
            StringBuffer sb = new StringBuffer();
            String line;
            // 获取操作系统对应的换行符
            String NL = System.getProperty("line.separator");
            while ((line = in.readLine()) != null) {
                sb.append(line + NL);
            }
            in.close();
            result = sb.toString();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (null != response) {
                    // 释放连接
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    public String post(String url, Object param) {
        CloseableHttpResponse response = null;
        BufferedReader in;
        String result = "";
        try {
            HttpPost httpPost = new HttpPost(url);
            RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(30000).setConnectionRequestTimeout(30000).setSocketTimeout(30000).build();
            httpPost.setConfig(requestConfig);
            httpPost.addHeader("Content-type", "application/json; charset=utf-8");
            httpPost.setHeader("Accept", "application/json");
            httpPost.setEntity(new StringEntity(JSON.toJSONString(param), Charset.forName("UTF-8")));
            response = httpClient.execute(httpPost);
            in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
            StringBuffer sb = new StringBuffer();
            String line;
            String NL = System.getProperty("line.separator");
            while ((line = in.readLine()) != null) {
                sb.append(line + NL);
            }
            in.close();
            result = sb.toString();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (null != response) {
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return result;
    }
}

使用

@RestController
@RequestMapping("/http")
public class HttpTestController {

    @Autowired
    private HttpClientUtil httpClientUtil;

    @GetMapping("test")
    public ApiResult test() {
        return ApiUtil.success();
    }

    @GetMapping("test1")
    public ApiResult test1() {
        String json = httpClientUtil.get("http://127.0.0.1:8888/http/test");
        return JSON.parseObject(json, new TypeReference<ApiResult>() {});
    }
}

详细使用可参考:https://www.cnblogs.com/qnlcy/p/15378446.html

2. OKhttp

OkHttp是一个高效的HTTP客户端,允许所有同一个主机地址的请求共享同一个socket连接;连接池减少请求延时;透明的GZIP压缩减少响应数据的大小;缓存响应内容,避免一些完全重复的请求。

当网络出现问题的时候OkHttp依然坚守自己的职责,它会自动恢复一般的连接问题,如果你的服务有多个IP地址,当第一个IP请求失败时,OkHttp会交替尝试你配置的其他IP,OkHttp使用现代TLS技术(SNI, ALPN)初始化新的连接,当握手失败时会回退到TLS 1.0。

使用方法

配置OkHttpClient。

使用示例

依赖配置

<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>3.10.0</version>
</dependency>

配置类

@Configuration
public class OkHttpConfig {
    @Bean
    public OkHttpClient okHttpClient() {
        return new OkHttpClient.Builder()
                // .sslSocketFactory(sslSocketFactory(), x509TrustManager())
                .retryOnConnectionFailure(false)
                .connectionPool(pool())
                .connectTimeout(30, TimeUnit.SECONDS)
                .readTimeout(30, TimeUnit.SECONDS)
                .writeTimeout(30, TimeUnit.SECONDS)
                .build();
    }

    @Bean
    public X509TrustManager x509TrustManager() {
        return new X509TrustManager() {
            @Override
            public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
            }

            @Override
            public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
            }

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[0];
            }
        };
    }

    @Bean
    public SSLSocketFactory sslSocketFactory() {
        try {
            //信任任何链接
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, new TrustManager[]{x509TrustManager()}, new SecureRandom());
            return sslContext.getSocketFactory();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Bean
    public ConnectionPool pool() {
        return new ConnectionPool(200, 5, TimeUnit.MINUTES);
    }
}

使用

@RestController
@RequestMapping("/http")
public class HttpTestController {

    @Autowired
    private OkHttpUtil okHttpUtil;

    @GetMapping("test")
    public ApiResult test() {
        return ApiUtil.success();
    }

    @GetMapping("test2")
    public ApiResult test2() {
        String json = okHttpUtil.get("http://127.0.0.1:8888/http/test", null);
        return JSON.parseObject(json, new TypeReference<ApiResult>() {});
    }
}

3. Retrofit

retrofit是现在比较流行的网络请求框架,可以理解为okhttp的加强版,底层封装了okhttp。准确来说,Retrofit是一个RESTful的http网络请求框架的封装。因为网络请求工作本质上是由okhttp来完成,而Retrofit负责网络请求接口的封装。

底层原理

应用程序通过Retrofit请求网络,实质上是使用Retrofit接口层封装请求参数、Header、Url等信息,之后由okhttp来完成后续的请求工作。在服务端返回数据后,okhttp将原始数据交给Retrofit,Retrofit根据用户需求解析。

Retrofit将okhttp请求抽象成java接口,采用注解描述和配置网络请求参数,用动态代理将该接口的注解“翻译”成一个Http请求,最后执行Http请求。

注意:接口中的每个方法的参数都要用注解标记,否则会报错。

Retrofit的优点

  • 超级解耦 ,接口定义、接口参数、接口回调不在耦合在一起
  • 可以配置不同的httpClient来实现网络请求,如okhttp、httpclient
  • 支持同步、异步、Rxjava
  • 可以配置不同反序列化工具类来解析不同的数据,如json、xml
  • 请求速度快,使用方便灵活简洁

相关注解

1. 请求方法

注解描述
@GETget请求
@POSTpost请求
@PUTput请求
@DELETEdelete请求
@PATCHpatch请求,该请求是对put请求的补充,用于更新局部资源
@HEADhead请求
@OPTIONSoptions请求
@HTTP通过注解,可以替换以上所有的注解,它拥有三个属性:method、path、hasBody

2. 请求头

注解描述
@Headers用于添加固定请求头,可以同时添加多个,通过该注解的请求头不会相互覆盖,而是共同存在
@Header用于添加不固定的header,作为方法的参数传入,它会更新已有请求头

3. 请求参数

注解描述
@Body多用于Post请求发送非表单数据,根据转换方式将实例对象转化为对应字符串传递参数,比如使用Post发送Json数据,添加GsonConverterFactory则是将body转化为json字符串进行传递
@Filed多用于Post方式传递参数,需要结合@FromUrlEncoded使用,即以表单的形式传递参数
@FiledMap多用于Post请求中的表单字段,需要结合@FromUrlEncoded使用
@Part用于表单字段,Part和PartMap与@multipart注解结合使用,适合文件上传的情况
@PartMap用于表单字段,默认接受类型是Map<String,RequestBody>,可用于实现多文件上传
@Path用于Url中的占位符
@Query用于Get请求中的参数
@QueryMap与Query类似,用于不确定表单参数
@Url指定请求路径

4. 请求和响应格式(标记)

注解描述
@FromUrlCoded表示请求发送编码表单数据,每个键值对需要使用@Filed注解
@Multipart表示请求发送form_encoded数据(使用于有文件上传的场景),每个键值对需要用@Part来注解键名,随后的对象需要提供值
@Streaming表示响应用字节流的形式返回,如果没有使用注解,默认会把数据全部载入到内存中,该注解在下载大文件时特别有用

使用方法

自定义请求接口,采用注解描述和配置请求参数。

使用示例

本示例不是直接使用的retrofit依赖,而是使用的retrofit整合springboot依赖。

retrofit依赖

<dependency>
    <groupId>com.squareup.retrofit2</groupId>
    <artifactId>retrofit</artifactId>
    <version>2.9.0</version>
</dependency>

retrofit整合springboot依赖

<dependency>
    <groupId>com.github.lianjiatech</groupId>
    <artifactId>retrofit-spring-boot-starter</artifactId>
    <version>2.0.2</version>
</dependency>

启动类配置

@SpringBootApplication
@RetrofitScan("com.joker.http.retrofit")
public class SpringbootApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootApplication.class, args);
    }

}

自定义接口

import com.github.lianjiatech.retrofit.spring.boot.annotation.RetrofitClient;
import com.joker.common.base.result.ApiResult;
import com.joker.pojo.User;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.http.*;
import java.util.Map;

@RetrofitClient(baseUrl = "http://127.0.0.1:8888")
public interface RetrofitHttpApi {

    @GET("http/test")
    ApiResult test();

    /**
     * 简单的GET请求
     * @Query:用于Get请求中的参数
     */
    @GET("http/test1")
    ApiResult test1(@Query("id") long id);

    /**
     * 不确定参数的GET请求
     * @QueryMap 与@Query类似,用于不确定表单参数。通过Map将不确定的参数存入,然后在方法体中带给网络接口。
     */
    @GET("http/test2")
    ApiResult test2(@QueryMap Map<String, Object> map);

    /**
     * From表单POST请求
     * @FormUrlEncoded:请求格式注解,表明请求实体是一个From表单,每个键值对需要使用@Field注解
     * @Field:表单参数,而且需要配合@FormUrlEncoded使用
     * @return
     */
    @FormUrlEncoded
    @POST("http/test3")
    ApiResult test3(@Field("name") String name, @Field("age") Integer age);

    /**
     * 不确定参数的From表单POST请求
     */
    @FormUrlEncoded
    @POST("http/test4")
    ApiResult test4(@FieldMap Map<String, Object> map);

    /**
     * json方式POST请求
     */
    @POST("http/test5")
    ApiResult test5(@Body User user);

    /**
     * 文件上传表单POST请求
     * @Multipart:表示请求实体是一个支持文件上传的表单,需要配合@Part和@PartMap使用,适用于文件上传
     * @Part:用于表单字段,适用于文件上传的情况,@Part支持三种类型:RequestBody、MultipartBody.Part任意类型
     * @PartMap:用于多文件上传, 与@FieldMap和@QueryMap的使用类似
     * @return
     */
    @Multipart
    @POST("http/test6")
    ApiResult test6(@Part("name") RequestBody name, @Part MultipartBody.Part file);

    /**
     * 多文件上传POST请求
     * @param map
     * @return
     */
    @Multipart
    @POST("http/test7")
    ApiResult test7(@PartMap Map<String, MultipartBody.Part> map);

    /**
     * 路径参数请求
     * @param id
     * @return
     */
    @GET("http/test8/{id}")
    ApiResult test8(@Path("id") Long id);

    /**
     * 请求头参数请求
     * @Header:请求头注解,用于添加不固定请求头
     * @param token
     * @return
     */
    @GET("http/test9")
    ApiResult test9(@Header("token") String token);

    /**
     * 请求头参数请求
     * @Headers:请求头注解,用于添加固定请求头,可以添加多个
     * @return
     */
    @Headers({"version:1.0","os:windows"})
    @GET("http/test10")
    ApiResult test10();

    /**
     * 动态url请求
     * @Url:将地址以参数的形式传入,请求方法注解中定义的url忽略
     * @param url
     * @return
     */
    @GET("http/test11")
    ApiResult test11(@Url String url);

    /**
     * 下载文件请求
     * @Streaming:响应体的数据用流的方式返回,使用于返回数据比较大,该注解在下载大文件时特别有用
     * @return
     */
    @Streaming
    @POST("http/test12")
    ResponseBody test12();

    /**
     * @HTTP:注解的作用是替换@GET、@POST、@PUT、@DELETE、@HEAD以及更多拓展功能
     * @return
     */
    @HTTP(method = "GET", path = "http/test13", hasBody = false)
    ApiResult test13();
}

详细使用可参考:https://blog.csdn.net/why_still_confused/article/details/108041657

4. RestTemplate

RestTemplate是Spring提供的用于访问Rest服务的客户端库。它提供了一套接口,实现这套接口的http库都可以通过RestTemplate来使用。

常用的有:

  1. JDK自带的HttpURLConnection
  2. Apache的HttpClient
  3. OKHttp

RestTemplate默认使用的http库是JDK自带的HttpURLConnection来建立HTTP连接(使用SimpleClientHttpRequestFactory客户端)。另外三方http库通过实现ClientHttpRequestFactory接口来自定义客户端,可以通过RestTemplate的setRequestFactory指定要使用的客户端。

ClientHttpRequestFactory接口的实现类:

  1. SimpleClientHttpRequestFactory(Spring默认使用的客户端)
  2. HttpComponentsClientHttpRequestFactory(Apache HttpClient使用的客户端)
  3. OkHttp3ClientHttpRequestFactory(OKHttp使用的客户端)

RestTemplate在spring-web包中。Spring项目有spring-web包即可,SpringBoot项目有spring-boot-starter-web包即可,如果要少使用Apache的HttpClient、OKHttp等相关三方http库,则还需要器对应的包。

RestTemplate内部模板使用HttpMessageConverter实例将HTTP消息转换为POJO和从POJO转换。主要MIME类型的转换器是默认注册的,也可以通过setMessageConverters方法注册其他转换器。

RestTemplate提供操作http的方法

方法名称支持的HTTP方法方法描述
getForObjectGET直接返回响应对象,可设置路径参数
getForEntityGET返回封装的响应对象,可设置路径参数
postForObjectPOST直接返回响应对象,可设置路径参数,可设置请求body和请求header
postForEntityPOST返回封装的响应对象,可设置路径参数,可设置请求body和请求header
postForLocationPOST返回URI对象,适用于返回网络资源的请求方式。可设置路径参数,可设置请求body和请求header
putPUT无返回值,可设置路径参数,可设置请求body和请求header
deleteDELETE无返回值,可设置路径参数
headForHeadersHEAD返回HttpHeaders,可设置路径参数
optionsForAllowOPTIONS返回Set<HttpMethod>,可设置路径参数
execute都支持直接返回响应对象,通用请求方法
exchange都支持返回封装的响应对象,通用请求方法

注意:封装的响应对象除了能获取到响应对象,还能额外获取到响应状态,响应Header信息。

使用方法

配置RestTemplate(如果不配置客户端,会使用默认的客户端SimpleClientHttpRequestFactory),就可以直接使用。

方法1

使用spring默认客户端SimpleClientHttpRequestFactory

    @Bean
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate();
        return restTemplate;
    }

方法2

使用Apache HttpClient客户端(HttpComponentsClientHttpRequestFactory)。

    @Bean
    @DependsOn("httpClient")
    public RestTemplate restTemplate3(HttpClient httpClient) {
        RestTemplate restTemplate = new RestTemplate(httpComponentsClientHttpRequestFactory(httpClient));
        setRestTemplate(restTemplate);
        return restTemplate;
    }
    
    @Bean
    public ClientHttpRequestFactory httpComponentsClientHttpRequestFactory(HttpClient httpClient) {
        return new HttpComponentsClientHttpRequestFactory();
    }

HttpClient的配置参考上面HttpClient的使用示例。

方法3

使用OKHttp客户端(OkHttp3ClientHttpRequestFactory)。

    @Bean
    @DependsOn("okHttpClient")
    public RestTemplate restTemplate4(OkHttpClient okHttpClient) {
        RestTemplate restTemplate = new RestTemplate(okHttp3ClientHttpRequestFactory(okHttpClient));
        setRestTemplate(restTemplate);
        return restTemplate;
    }

	@Bean
    public ClientHttpRequestFactory okHttp3ClientHttpRequestFactory(OkHttpClient okHttpClient) {
        return new OkHttp3ClientHttpRequestFactory(okHttpClient);
    }

OkHttpClient的配置参考上面OKhttp的使用示例。

使用示例

1.先按上面的使用方法配置好RestTemplate。

2.进行接口测试,示例如下:

    @Autowired
    private RestTemplate restTemplate;
    
	@GetMapping("test4")
    public ApiResult test4() {
        // 1.Get请求
        ApiResult result = restTemplate.getForObject(getUrl("get"), ApiResult.class);
        System.out.println("Get请求:" + JSON.toJSONString(result));

        // 2.设置路径参数的Get请求
        result = restTemplate.getForObject(getUrl("get/{id}"), ApiResult.class, 123);
        System.out.println("设置路径参数的Get请求:" + JSON.toJSONString(result));

        // 3.封装返回对象的Get请求
        ResponseEntity<ApiResult> responseEntity = restTemplate.getForEntity(getUrl("get"), ApiResult.class);
        System.out.println("封装返回对象的Get请求:" + responseEntity.getBody());

        // 4.设置header的Get请求
        HttpHeaders headers = new HttpHeaders();
        headers.add("token", "token");
        ResponseEntity<ApiResult> response = restTemplate.exchange(getUrl("get"), HttpMethod.GET, new HttpEntity<String>(headers), ApiResult.class);
        System.out.println("设置header的Get请求:" + response.getBody());

        // 5.Post请求
        User user = new User();
        user.setId("1");
        result = restTemplate.postForObject(getUrl("post"), user, ApiResult.class);
        System.out.println("Post请求:" + result);

        // 6.设置header的Post请求
        response = restTemplate.postForEntity(getUrl("post"), new HttpEntity<>(user, headers), ApiResult.class);
        System.out.println("设置header的Post请求:" + response.getBody());

        // 7.设置header的put请求
        // 无返回值
        restTemplate.put(getUrl("put"), new HttpEntity<>(user, headers));
        // 带返回值
        response = restTemplate.exchange(getUrl("put"), HttpMethod.PUT, new HttpEntity<>(user, headers), ApiResult.class);
        System.out.println("设置header的put请求:" + response.getBody());

        // 8.设置路径参数的del请求
        // 无返回值
        restTemplate.delete(getUrl("delete/{id}"), 123);
        // 带返回值
        response = restTemplate.exchange(getUrl("delete/{id}"), HttpMethod.DELETE, null, ApiResult.class,123);
        System.out.println("设置路径参数的del请求:" + response.getBody());
        return ApiUtil.success();
    }
  • 6
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值