互联网大厂技术-HTTP请求-Springboot整合Feign更优雅地实现Http服务调用

目录

一、SpringBoot快速整合Feign

1.添加Pom依赖

2.启动类添加注解

3.引用Feign服务

二、为请求添加Header的3种方式

1.添加固定header

2.通过接口签名添加header

3.动态添加header

三、为请求添加超时配置

1.默认超时时间

3.超时异常

4.全局超时配置

5.为单个服务设置超时配置

四、为请求配置客户端负载均衡模式

五、Feign日志

1.日志级别

2.日志配置类

3.配置文件

六、高阶配置

七、Feign与Springboot版本

八、技术问题

no suitable HttpMessageConverter found for response type



本章内容讲解重点目标以及面向用户

本章目标

了解feign的原理

掌握feign的使用

学会feign多种header的设置方式

学会feign日志控制

了解feign高阶配置项

其他开发注意事项

面向用户初、中、高阶的研发同学

很多时候,我们查看一些高阶架构同学在写Http服务调用时,调试跟踪代码时发现就只有接口签名,没有想okhttp那样写一些调用过程的代码,代码看起来风格清爽、优雅并不失逻辑严谨,读完该篇文章,您会掌握其实现方案,并提供demo协助您完成实战,有技术问题可以私信请教;

一、SpringBoot快速整合Feign

1.添加Pom依赖

 <properties>
        <spring-cloud-feign.version>3.1.3</spring-cloud-feign.version>
    </properties>

<parent>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-parent</artifactId>
   <version>2.7.10</version>
</parent>
<dependencies>
<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-openfeign</artifactId>
   <version>${spring-cloud-feign.version}</version>
</dependency>
</dependencies>

2.启动类添加注解

@EnableFeignClients

3.引用Feign服务

@RestController
@RequestMapping("/stock")
public class StockController {

    @Autowired
    private LocalFeignService service;

    @GetMapping("/get")
    public String get(){
        service.add("10");
        return "Hello world";
    }
}

二、为请求添加Header的3种方式

1.添加固定header

@RestController
public class HomeController {

    @Resource
    private FeignClientService feignClientService;

    

    @RequestMapping(value = "/add")
    public String add(@RequestBody FeignReq req) {
        return "ok";
    }

   
    @RequestMapping("/test-add")
    public Object testAdd() {
        FeignReq req = new FeignReq();
        req.setId(System.currentTimeMillis());
        return feignClientService.add(req);
    }

}

在@PostMapping注解的headers参数中添加固定的header值,也包括一些从配置文件读取的配置项作为header值

@Component
@FeignClient(name = "feignClientService", url = "http://localhost:8081")
public interface FeignClientService {

    @PostMapping(value = "/add", headers = {"Authorization=myFeignSignToken", "Content-Type=text/plain", "App=${my.name}"})
    public String add(@RequestBody FeignReq req);

}

浏览器访问:http://localhost:8081/test-add

2.通过接口签名添加header

@RestController
public class HomeController {



    @Resource
    private FeignClientService feignClientService;


    @PostMapping(value = "/query")
    public String query(@RequestParam("queryName") String queryName) {

        return queryName + "ok";
    }


    @RequestMapping("/test-query")
    public Object testQuery() {
        Map<String, String> map = new HashMap<>();
        map.put("token", "ikong_token"+System.currentTimeMillis());
        return feignClientService.query("ikong", map);
    }

}

重点是在Map类型的headers,这里通过接口签名的@RequestHeader注解将Map对象转化成请求header

@Component
@FeignClient(name = "feignClientService", url = "http://localhost:8081", configuration = TestRequestInterceptor.class)
public interface FeignClientService {

    @PostMapping(value = "/query")
    public String query(@RequestParam("queryName") String queryName, @RequestHeader Map<String, String> headers);

}

浏览器访问:http://localhost:8081/test-query

3.动态添加header

@RestController
public class HomeController {


    @Resource
    private FeignClientService feignClientService;

    @RequestMapping("/search")
    public Object search(@RequestBody FeignReq req) {
        return "ok";
    }

   
    @RequestMapping("/test-search")
    public Object testSearch() {
        FeignReq req = new FeignReq();
        req.setId(System.currentTimeMillis());
        return feignClientService.search(req);
    }


}

@Component
@FeignClient(name = "feignClientService", url = "http://localhost:8081", configuration = TestRequestInterceptor.class)
public interface FeignClientService {


    @PostMapping("/search")
    public String search(@RequestBody FeignReq req);

}

通过FeignClient注解注入configuration = TestRequestInterceptor.class,在TestRequestInterceptor实现header动态添加能力


public class TestRequestInterceptor implements RequestInterceptor {

    @Override
    public void apply(RequestTemplate template) {
        template.header(HttpHeaders.AUTHORIZATION, createApiSign());
    }

    /**
     * 创建接口签名
     *
     * @return
     */
    private String createApiSign() {
        return UUID.randomUUID().toString();
    }

}

浏览器访问:http://localhost:8081/test-search

三、为请求添加超时配置

1.默认超时时间

connectiontimeout : 10s,readtimeout : 60s

  public static class Options {
 
    private final int connectTimeoutMillis;
    private final int readTimeoutMillis;
 
    public Options(int connectTimeoutMillis, int readTimeoutMillis) {
      this.connectTimeoutMillis = connectTimeoutMillis;
      this.readTimeoutMillis = readTimeoutMillis;
    }
 
    public Options() {
      this(10 * 1000, 60 * 1000);
    }
 
    /**
     * Defaults to 10 seconds. {@code 0} implies no timeout.
     *
     * @see java.net.HttpURLConnection#getConnectTimeout()
     */
    public int connectTimeoutMillis() {
      return connectTimeoutMillis;
    }
 
    /**
     * Defaults to 60 seconds. {@code 0} implies no timeout.
     *
     * @see java.net.HttpURLConnection#getReadTimeout()
     */
    public int readTimeoutMillis() {
      return readTimeoutMillis;
    }
  }

3.超时异常

exception:feign.RetryableException: connect timed out executing POST http://xxx.ik.com/your/api

4.全局超时配置

feign.client.config.default.connectTimeout=5000
feign.client.config.default.readTimeout=5000

5.为单个服务设置超时配置

 要实现不同服务配备不同的超时时间,可按如下配置进行

feign.client.config.yourService.connectTimeout=5
feign.client.config.yourService.readTimeout=5

四、为请求配置客户端负载均衡模式

OpenFeign只是一种Rest客户端,本身不具备任何的负载均衡操作。 OpenFeign底层调用的还是Netflix Ribbon负载均衡组件,那我们在使用OpenFeign实现服务调用时,如何修改负载均衡策略呢?

自定义Ribbon的负载均衡配置

@Configuration
// name为服务名
@RibbonClient(name = "my-provider", configuration = MyLoadBalanceConfiguration.class)
public class MyLoadBalanceConfiguration {

    @Bean
    public IRule ribbonRule() {
        return new RandomRule(); // 采用随机策略
    }
}

我们这里使用的是随机策略,默认为轮询策略。

Ribbon提供可选负载均衡分类

  1. 随机策略——RandomRule
  2. 轮询策略——RoundRobinRule 注:Ribbon默认策略
  3. 重试策略——RetryRule
  4. 最低并发策略——BestAvailableRule
  5. 可用过滤策略——AvailabilityFilteringRule、过滤掉那些因为一直连接失败的被标记为circuit tripped的后端server,并过滤掉那些高并发的的后端server(active connections 超过配置的阈值),性能仅次于最低并发策略。
  6. 响应时间加权策略——WeightedResponseTimeRule,每隔30秒计算一次服务器响应时间,以响应时间作为权重,响应时间越短的服务器被选中的概率越大。
  7. 区域权衡策略——ZoneAvoidanceRule

Ribbon的负载均衡策略使用建议
一般情况下,推荐使用最低并发策略,这个性能比默认的轮询策略高很多。

五、Feign日志

feign的日志是建立在 debug日志模式的基础上的,不管是全局配置还是局部配置,代码配置还是属性配置,都需要先把日志模式调成debug模式:(下面与调用FeignClientService接口的日志模式为例)

1.日志级别

OpenFeign的日志级别有

  • NONE: 默认的,不显示任何日志。

  • BASIC: 仅记录请求方法、URL、响应状态码以及执行时间。

  • HEADERS:除了BASIC 中自定义的信息外,还有请求和响应的信息头。

  • FULL: 除了HEADERS中定义的信息外, 还有请求和响应的正文以及元数据。

2.日志配置类

@Configuration
public class OpenFeignLogConfig {
  @Bean
  Logger.Level feignLoggerLevel(){
    return Logger.Level.FULL;
  }
}

3.配置文件

logging:
  level:
  *[feign日志以什么级别监控哪个接口]:
  com.ik.ikong.service.FeignClientService: debug

六、高阶配置

七、Feign与Springboot版本

版本对照关系如下,详情也可以点击这里的链接在官网查看最新版本兼容关系

八、技术问题

在调用接口时候idea报错

no suitable HttpMessageConverter found for response type

解决过程

1.放开日志

@Configuration
public class FeignConfiguration {

    @Bean
    public feign.Logger logger() {
        return new Slf4jLogger();
    }
    @Bean
    public Logger.Level level() {
        return Logger.Level.FULL;
    }
}
logging:
  level:
    feign.Logger: debug

日志详细

从放开的日志来看,接口返回的head里:content-type: text/html; charset=UTF-8

虽然我在接口签名上增加了produces、consumes

@PostMapping(value = "/xxxxx/your/api", produces = "application/json;charset=utf-8", consumes = "application/json;charset=utf-8")

可以看到毫无效果,仍旧异常:no suitable HttpMessageConverter found for response type

猜想原生的http返回值只对application/json类型做了泛型的反序列化处理,是对接口返回的content-type: text/html;并不能进行json反序列化处理,遂增加该类型的json反序列化处理;

@Bean
    public HttpMessageConverters customConverters() {
        MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
        mappingJackson2HttpMessageConverter.setSupportedMediaTypes(Arrays.asList(MediaType.TEXT_HTML,MediaType.APPLICATION_JSON));
        return new HttpMessageConverters(false, Arrays.asList(mappingJackson2HttpMessageConverter, new StringHttpMessageConverter()));
    }

重点在mappingJackson2HttpMessageConverter.setSupportedMediaTypes(Arrays.asList(MediaType.TEXT_HTML,MediaType.APPLICATION_JSON));

最后成功完成增加content-type: text/html的json反序列化;

参考:Spring Cloud

Feign实现服务间的Http调用。_feign http调用_半命i的博客-CSDN博客

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码者人生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值