@RequestHeader注解
第一种方式,这个很简单,在方法参数列表里上加注解@RequestHeader就行。
@PostMapping(value = "/getStuDetail")
public ReturnInfo getStudentDetail(@RequestBody Map map,@RequestHeader(name = "id") String id);
RequestInterceptor接口
第二种方法,实现RequestInterceptor接口,重写apply函数。
@Configuration
public class FeignRequestInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate template) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
Enumeration<String> headerNames = request.getHeaderNames();
if (headerNames != null) {
while (headerNames.hasMoreElements()) {
String name = headerNames.nextElement();
String values = request.getHeader(name);
// 调用 template.header设置header信息
template.header(name, values);
}
}
}
}
@Component
@FeignClient(value = "xxxxxxxxx",configuration = FeignRequestInterceptor.class)
public interface FeignProvider {
}
在apply调用template.header设置header信息即可,然后发起feign请求的Provider设置configuration = FeignRequestInterceptor.class即可。
正确使用多个FeignRequestInterceptor
在FeignRequestInterceptor上加@Configuration这种方式,会影响所有的Feign请求。
如果有多个RequestInterceptor实现类并加上了@configuration,不管configuration参数指定与否,
所有的Feign请求会循环走完所有RequestInterceptor的apply函数。
这个时候你想要每个不同的FeignProvider走指定的RequestInterceptor的apply函数怎么办呢?
那就是在每个FeignRequestInterceptor上不要添加@Configuration以及@Component注解,什么注解都不要加,然后在每个单独的@FeignClient去指定不同的FeignRequestInterceptor。
FeignRequestInterceptor特殊的使用方式
当你想要多FeignRequestInterceptor时,又想要用@Configuration或者@Component注入一些Bean到FeignRequestInterceptor中怎么办呢?
我就遇到了此种情形,我的FeignRequestInterceptor需要使用到RedisTemplate对象来操作Redis,但是如果你加@Configuration声明为组件,则多RequestInterceptor时会乱套。
如果你不加@Configuration声明为组件,则你无法注入RedisTemplate。
这个时候可以绕过这个接口。下面是操作方法。
import feign.RequestInterceptor;
// 接口继承feign的RequestInterceptor
public class ApiConfiguration implements RequestInterceptor {
// 内部包含一个自定义的requestInterceptor
private RedisRequestInterceptor requestInterceptor;
public ApiConfiguration(RedisRequestInterceptor requestInterceptor) {
this.requestInterceptor = requestInterceptor;
}
@Override
public void apply(RequestTemplate template) {
requestInterceptor.apply(template);
}
}
// 自己模仿feign的RequestInterceptor定义一个ApiRequestInterceptor
public interface ApiRequestInterceptor {
/**
* 自定义的feign 请求拦截
*
* @param template
*/
void apply(RequestTemplate template);
}
// 操作redis的请求拦截器
@Configuration
public class RedisRequestInterceptor implements ApiRequestInterceptor {
private final RedisTemplate<String, String> redisTemplate;
public RedisRequestInterceptor(RedisTemplate<String, String> redisTemplate) {
this.redisTemplate = redisTemplate;
}
@Override
public void apply(RequestTemplate template) {
// 从redis中取header, 只是一个示例。
String header = redisTemplate.opsForValue().get("header");
// 写到header中
template.header("header", header);
}
}
@FeignClient(name = Const.SERVICE_NAME, configuration = {ApiConfiguration.class})
@Primary
public interface ServiceProvider {
}
ServiceProvider指定的ApiConfiguration没有加任何注解,内部定义了一个RedisRequestInterceptor对象。
然后真正的RedisRequestInterceptor上加上@Configuration注解并实现ApiRequestInterceptor接口。
这样feign运行时就会找到RedisRequestInterceptor这个bean并运行。