2024年07月20日   码农之路   101 次浏览
首先在讲解openfeign拦截器之前,需要先了解一下feign的请求流程:
从上面的流程我们就知道可以从以下几个节点进行数据的拦截:Encoder、RequestInterceptor、Decoder,我们可以看下源码是怎么实现的。
FeignClientsConfiguration默认配置类中的默认Encoder、Decoder配置:
@Bean
@ConditionalOnMissingBean
public Decoder feignDecoder(ObjectProvider<HttpMessageConverterCustomizer> customizers) {
return new OptionalDecoder(new ResponseEntityDecoder(new SpringDecoder(messageConverters, customizers)));
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnMissingClass("org.springframework.data.domain.Pageable")
public Encoder feignEncoder(ObjectProvider<AbstractFormWriter> formWriterProvider,
ObjectProvider<HttpMessageConverterCustomizer> customizers) {
return springEncoder(formWriterProvider, encoderProperties, customizers);
}
RequestInterceptor的逻辑在FeignClientFactoryBean类中可以看到:
if (config.getRequestInterceptors() != null && !config.getRequestInterceptors().isEmpty()) {
// this will add request interceptor to builder, not replace existing
for (Class<RequestInterceptor> bean : config.getRequestInterceptors()) {
RequestInterceptor interceptor = getOrInstantiate(bean);
builder.requestInterceptor(interceptor);
}
}
// 这段代码在SynchronousMethodHandler中
Request targetRequest(RequestTemplate template) {
for (RequestInterceptor interceptor : requestInterceptors) {
interceptor.apply(template);
}
return target.apply(template);
}
好了,了解完源码,我们就可以参照源码来实现自己的需求了。
1、首先实现一个RequestInterceptor对请求进行拦截:
/**
* feign 请求拦截器
*/
@Component
public class FeignRequestInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
HttpServletRequest httpServletRequest = ServletUtils.getRequest();
if (httpServletRequest == null) {
return;
}
Map<String, String> headers = ServletUtils.getHeaders(httpServletRequest);
// 这里可以对请求做任何处理,比如这里对headers进行处理
String userId = headers.get(SecurityConstants.DETAILS_USER_ID);
if (StringUtils.isNotEmpty(userId)) {
requestTemplate.header(SecurityConstants.DETAILS_USER_ID, userId);
}
}
}
2、然后实现一个Decoder对结果进行拦截:
/** * 对feign的返回结果进行统一处理 */ @Component public class FeignResponseDecoder implements Decoder { private final SpringDecoder springDecoder; public FeignResponseDecoder(SpringDecoder springDecoder) { this.springDecoder = springDecoder; } @Override public Object decode(Response response, Type type) throws IOException, FeignException { Object decode = springDecoder.decode(response, type); // 这里可以对 springDecoder 结果进行处理,下面是判断结果是否正常 if (decode instanceof R) { R r = (R) decode; // 判断返回结果是否正常,不正常的抛出异常 if (r.isError()) { throw new DecodeException(r.getCode(), r.getMsg(), response.request()); } } return decode; } }
3、定义一个配置类FeignAutoConfiguration覆盖默认的配置:
/**
* Feign 配置注册
**/
@Configuration
public class FeignAutoConfiguration {
@Bean
public RequestInterceptor requestInterceptor() {
return new FeignRequestInterceptor();
}
@Bean
public Decoder decoder(ObjectFactory<HttpMessageConverters> msgConverters, ObjectProvider<HttpMessageConverterCustomizer> customizers) {
// 这里参考的源码,因为SpringDecoder已经帮我们做了很多基础工作,
// 所以只需要对SpringDecoder进行再次包装即可。
return new OptionalDecoder((new ResponseEntityDecoder(new FeignResponseDecoder(new SpringDecoder(msgConverters, customizers)))));
}
}
4、 Encoder的使用就留给你们自己去完成啦^_^
>>> Hello World <<<
这篇内容是否帮助到你了呢?
如果你有任何疑问或有建议留给其他朋友,都可以给我留言。