openfeign应用汇总(二)
openfeign应用汇总(二)
1、开启feign日志
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import feign.Logger;
import feign.codec.Decoder;
import feign.codec.ErrorDecoder;
@Configuration
public class FeignClientConfiguration{
@Bean
public Logger.Level feignLogLevel(){
// 配置日志级别
return Logger.Level.FULL;
}
@Bean
public Decoder feignDefDecoder() {
return new FeignResultDecoder();
}
@Bean
public ErrorDecoder feignErrorDecoder() {
return new FeignErrorDecoder();
}
}
配置文件形式配置
feign:
client:
config:
default: #此处写的是服务名称,针对我们feign微服务的配置,如果是default就是全局配置
loggerLevel: FULL #配置Feign的日志级别,相当于代码配置方式中的Logger
日志级别 | 打印内容 |
NONE(默认 | 不记录任何日志 |
BASIC | 仅记录请求方法、URL、响应状态码以及执行时间(适合生产) |
HEADERS | 记录BASIC基础上,记录请求和响应的header |
FULL | 记录请求和响应header、body和元数据 |
2、openfeign设置header的5种方式
- 在@RequestMapping注解里添加headers属性
- 在方法参数前面添加@RequestHeader注解
- 在方法或者类上添加@Headers的注解
- 在方法参数前面添加@HeaderMap注解
- 实现RequestInterceptor接口
@PostMapping(value = "/weixin/api", headers = {"Content-Type=application/json;charset=UTF-8", "App-Secret=${app.secret}"}) void saveUser(@RequestBody User user);
@GetMapping(value = "/getUser")
public User getUser(@RequestBody User user, @RequestHeader("Authorization") String token);
###设置多个headers
1@PostMapping(value = "/getUser") 2 public User getUser(@RequestBody User user, @RequestHeader MultiValueMap<String, String> headers);
@FeignClient(url = "${user.api.url}", name = "user", configuration = FeignClientConfiguration.class) public interface UserFeignClient { @RequestLine("GET /{id}") @Headers({"Content-Type: application/json;charset=UTF-8", "Authorization: {token}"}) public User findById(@Param("id") String id, @Param("token") String token); } ###使用feign自带契约 ####@Headers不起作用,其实@Headers注解没有生效的原因是:官方的Contract没有生效 ##### @Configuration public class Configuration { @Bean public Contract feignContract() { return new feign.Contract.Default(); } }
###使用feign自带契约
@FeignClient(url = "${user.api.url}", name = "user", configuration = FeignClientConfiguration.class) public interface UserFeignClient { @RequestLine("GET /{id}") public User findById(@Param("id") String id, @HeaderMap HttpHeaders headers); }
@Configuration public class FeignRequestInterceptor implements RequestInterceptor { @Override public void apply(RequestTemplate template) { template.header("Authorization", token); } }
3、修改header参数值(实现requestInterceptor)
package com.kayak.integration.client.dto.weixin; import java.util.Collection; import java.util.Iterator; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import feign.RequestInterceptor; import feign.RequestTemplate; public class WxRequestInceptor implements RequestInterceptor{ final Logger logger = LoggerFactory.getLogger(this.getClass()); private static final String header_key = "Authorization"; private Iterator<String> iterator; @Override public void apply(RequestTemplate paramRequestTemplate) { Map<String, Collection<String>> headersMap = paramRequestTemplate.headers();#获取报文头中的参数信息 if(headersMap != null) { Collection<String> value = headersMap.get(header_key); if(value != null) { iterator = value.iterator(); while(iterator.hasNext()){ String auth = iterator.next(); if(auth.startsWith("WECHATPAY2-SHA256-RSA2048") && auth.contains(", ")) { paramRequestTemplate.removeHeader(header_key); paramRequestTemplate.header(header_key, auth.replaceAll(", ", ",")); } } } }else { logger.info("headersMap is null"); return ; } ####修改上下文中的header // ServletRequestAttributes reqAttr = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes(); // logger.info("reqAttr >>>"+reqAttr); // if(Objects.isNull(reqAttr)) { // return ; // } // HttpServletRequest request = reqAttr.getRequest(); // Enumeration<String> headerNames = request.getHeaderNames(); // if(headerNames != null) { // while(headerNames.hasMoreElements()) { // String name = headerNames.nextElement(); // String value = request.getHeader(name); // logger.info("name "+name+";value"+value); // } // } // String auth = request.getHeader(header_key); // logger.info("auth "+auth); // if(auth != null) { // paramRequestTemplate.header(header_key, auth.replaceAll(", ", ",")); // } } }
3、Feign接口的熔断机制为:线程模式;
自定义了一个RequestInterceptor实现类
,就会导致hystrix熔断机制失效,接口调用异常(404、null)
原因:
- 在feign调用之前,会走RequestInterceptor拦截器,拦截器中使用了
ServletRequestAttributes
获取请求数据; - 默认feign使用的是线程池模式,当开启熔断的时候,负责熔断的线程和执行Feign接口的线程不是同一个线程,ServletRequestAttributes取到的将会是空值。
解决方案:
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 30000
strategy: SEMAPHORE ####线程隔离
4、开启RequestInterceptor的4种方式
- @Bean方法将
RequestInterceptor实现类
注入到Spring容器 - 配置文件形式全局生效
- 在某个接口针对类生效
- 配置方式针对某个服务生效
方式一: @Configuration public class MyConfiguration { @Bean public RequestInterceptor requestInterceptor() { return new MyFeignRequestInterceptor(); } } 方式二: feign: client: config: default: ####全局生效 connectTimeout: 5000 readTimeout: 5000 loggerLevel: full # 拦截器配置(和@Bean的方式二选一) requestInterceptors: - com.yew.feign.config.MyFeignRequestInterceptor 方式三: 在@FeignClient注解中指定configuration属性为RequestInterceptor实现类
@FeignClient(Configuration=MyRequestInterceptor.class) 方式四: feign: client: config: service-A: ####指定服务生效 connectTimeout: 5000 readTimeout: 5000 loggerLevel: full # 拦截器配置(和@Bean的方式二选一) requestInterceptors: - com.yew.feign.config.MyFeignRequestInterceptor
posted on 2023-08-07 21:35 VincentYew 阅读(41) 评论(0) 编辑 收藏 举报