SpringBoot优雅的http客户端工具(Retrofit)

平时开发项目,避免不了其他服务接口调用,一般http客户端使用都是hutool的httputil、okhttp,但是还是觉得麻烦!发现“Retrofit”客户端工具非常好用,推荐给大家。

简介

Retrofit能够支持接口的方式发起http请求,类似于Feign申明式接口调用。


11.png

目前,java常用的开发框架是springboot,遗憾的是Retrofit官方并不支持。但是,有位开发者做了增强。


12.png

Springboot依赖使用

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

使用

  • application.yml 添加其他服务接口地址,可以自己模拟服务接口
thirdUrl:
  zh: https://test:20441/api/
  eye: http://test:2045/api/
eyeSkyToken: xxxxx
retrofit:
  # 连接池配置
  pool:
    # test1连接池配置
    test1:
      # 最大空闲连接数
      max-idle-connections: 3
      # 连接保活时间(秒)
      keep-alive-second: 100
  # 是否禁用void返回值类型
  disable-void-return-type: false

  # 全局转换器工厂
  global-converter-factories:
    - com.github.lianjiatech.retrofit.spring.boot.core.BasicTypeConverterFactory
    - retrofit2.converter.jackson.JacksonConverterFactory
  # 全局调用适配器工厂
  global-call-adapter-factories:
    - com.github.lianjiatech.retrofit.spring.boot.core.BodyCallAdapterFactory
    - com.github.lianjiatech.retrofit.spring.boot.core.ResponseCallAdapterFactory

  # 日志打印配置
  log:
    # 启用日志打印
    enable: true
    # 日志打印拦截器
    logging-interceptor: com.github.lianjiatech.retrofit.spring.boot.interceptor.DefaultLoggingInterceptor
    # 全局日志打印级别
    global-log-level: error
    # 全局日志打印策略
    global-log-strategy: basic
  # 重试配置
  retry:
    # 是否启用全局重试
    enable-global-retry: true
    # 全局重试间隔时间
    global-interval-ms: 1
    # 全局最大重试次数
    global-max-retries: 1
    # 全局重试规则
    global-retry-rules:
      - response_status_not_2xx
      - occur_io_exception
    # 重试拦截器
    retry-interceptor: com.github.lianjiatech.retrofit.spring.boot.retry.DefaultRetryInterceptor

  # 熔断降级配置
  degrade:
    # 是否启用熔断降级
    enable: true
    # 熔断降级实现方式
    degrade-type: sentinel
    # 熔断资源名称解析器
    resource-name-parser: com.github.lianjiatech.retrofit.spring.boot.degrade.DefaultResourceNameParser
  # 全局连接超时时间,还有局部的,在@RetrofitClient注解上可以设置超时时间,针对当前接口生效,优先级更高。具体字段有connectTimeoutMs、readTimeoutMs、writeTimeoutMs、callTimeoutMs等
  global-connect-timeout-ms: 5000
  # 全局读取超时时间
  global-read-timeout-ms: 5000
  # 全局写入超时时间
  global-write-timeout-ms: 5000
  # 全局完整调用超时时间
  global-call-timeout-ms: 0
  • 创建请求接口类
/**
 * 
 * 请求格式注解,请求实体是一个From表单
 * @Field 必须结合@FormUrlEncoded注解一起使用
 *
 */
@RetrofitClient(baseUrl = "${thirdUrl.zh}")
# 拦截器
@Intercept(handler = TimeStampInterceptor.class,include = "/api/**")
public interface HttpZhApi {
    @FormUrlEncoded
    @POST("Token")
    String Token(@Field("UserName")String userName,@Field("APIPwd")String apiPwd);
}

注意:@Field 必须结合@FormUrlEncoded注解一起使用,否则post请求无法接收参数

  • 请求接口同时,默认添加timestamp参数
/**
 * 注解式拦截器
 * 们希望某个接口下的某些http请求执行统一的拦截处理逻辑。为了支持这个功能
 */
@Component
public class TimeStampInterceptor extends BasePathMatchInterceptor {
    @Override
    protected Response doIntercept(Chain chain) throws IOException {
        Request request = chain.request();
        HttpUrl url = request.url();
        long timestamp = System.currentTimeMillis();
        HttpUrl newUrl = url.newBuilder()
                .addQueryParameter("timestamp", String.valueOf(timestamp))
                .build();
        Request newRequest = request.newBuilder()
                .url(newUrl)
                .build();
        return chain.proceed(newRequest);
    }
}

  • controller测试接口
@RestController
@RequestMapping("zhDemo")
public class ZhController {
    @Autowired
    HttpZhApi httpZhApi;
    @RequestMapping("token")
    public String getToken(String userName,String apiPwd){
       return  httpZhApi.Token(userName,apiPwd);
    }
13.png
  • 调整日志级别、打印策略
log:
    # 启用日志打印
    enable: true
    # 日志打印拦截器
    logging-interceptor: com.github.lianjiatech.retrofit.spring.boot.interceptor.DefaultLoggingInterceptor
    # 全局日志打印级别
    global-log-level: info
    # 全局日志打印策略
    global-log-strategy: body

修改日志策略global-log-strategy:body
响应结果

14.png

日志配置说明

  • Retrofit支持四种日志打印策略
  1. NONE:不打印日志;
  2. BASIC:只打印日志请求记录;
  3. HEADERS:打印日志请求记录、请求和响应头信息;
  4. BODY:打印日志请求记录、请求和响应头信息、请求和响应体信息
  • 全局超时时间
 global-connect-timeout-ms: 5000
  # 全局读取超时时间
  global-read-timeout-ms: 5000
  # 全局写入超时时间
  global-write-timeout-ms: 5000
  # 全局完整调用超时时间
  global-call-timeout-ms: 0
  • 重试规则global-retry-rules支持如下三种配置。
    1. RESPONSE_STATUS_NOT_2XX:响应状态码不是2xx时执行重试;
    2. OCCUR_IO_EXCEPTION:发生IO异常时执行重试;
    3. OCCUR_EXCEPTION:发生任意异常时执行重试。

请求添加头token

  • 定义token注解
@Target(ElementType.TYPE)
@Documented
@InterceptMark
public @interface EyeSkyToken {
    /**
     * 密钥key
     * 支持占位符形式配置。
     *
     * @return
     */
    String authorization();

    /**
     * 拦截器匹配路径
     *
     * @return
     */
    String[] include() default {"/**"};

    /**
     * 拦截器排除匹配,排除指定路径拦截
     *
     * @return
     */
    String[] exclude() default {};

    /**
     * 处理该注解的拦截器类
     * 优先从spring容器获取对应的Bean,如果获取不到,则使用反射创建一个!
     *
     * @return
     */
    Class<? extends BasePathMatchInterceptor> handler() default EyeSkyTokenInterceptor.class;
}

  • 自定义拦截器,所有请求添加授权header
@Setter
public class EyeSkyTokenInterceptor extends BasePathMatchInterceptor {
    private String authorization;
    @Override
    protected Response doIntercept(Chain chain) throws IOException {
            Request request = chain.request();
            Request newReq = request.newBuilder()
                    .addHeader("Authorization", authorization)
                    .build();
            return chain.proceed(newReq);

    }
}
  • 申明式请求接口
@RetrofitClient(baseUrl = "${thirdUrl.eye}",poolName = "test1")
@EyeSkyToken(authorization = "${eyeSkyToken}")
public interface HttpEyeSkyApi {
    @GET("baseinfoV2/2.0")
    String getCompanyInfo(@QueryMap Map<String, Object> map);

}

Retrofit 请求参数支持Map,详细查看官网

  • controller 测试接口调用
    @Autowired
    HttpEyeSkyApi eyeSkyApi;
    @RequestMapping("/companyInfo")
    public String getCompanyInfo(String companyName) throws UnsupportedEncodingException {
        map.put("keyword",companyName);
        return eyeSkyApi.getCompanyInfo(map);
    }

对比使用HttpUtil,通过Retrofit在单体应用项目中,可以使用类似Feign申明式接口这种方式。retrofit-spring-boot-starter提供的功能远不止于此,它还能支持微服务间的调用和熔断降级!

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容