feign拦截器和解码器

Feign拦截器和解码器

业务需求

在Spring Cloud的项目中,A服务使用Feign调用B服务的某个接口,如果需要传递全局认证token或参数,在方法参数里面加相应字段的方式显然是不可取的。

首先想到的是AOP方式,使用切面拦截Feign方法,在AOP切面里面向方法参数里面添加数据,Feign方法执行完成之后,从响应对象里面获取返回的数据,这样的方式可以解决数据的传递和接收,但也必将需要方法参数和响应对象的支持,与业务耦合,并不是合理的架构实现方案。

如果有某种机制可以拦截到Feign的请求对象和响应对象,便可以获取到请求头和响应头,就可以使用请求头和响应头来传递数据。

经过一番调查,了解到Feign的RequestInterceptor可以拦截到Feign请求,可以获取到请求对象和请求头,但是RequestInterceptor无法处理响应。

于是又进行调查,得知解码器Decoder是对响应进行解码的组件,可以获取到响应对象和响应头。

在调查过程中,还有另外的收获:FeignClientsConfiguration类。

FeignClientsConfiguration类

Feign默认配置类是FeignClientsConfiguration类,该类定义了Feign默认的编码器、解码器、所使用的契约等。

Spring Cloud允许通过注解@FeignClient的configuration属性自定义Feign配置,自定义配置的优先级比FeignClientsConfiguration要高。

这个类的核心代码如下:

@Configuration
public class FeignClientsConfiguration {

	@Autowired
	private ObjectFactory<HttpMessageConverters> messageConverters;

	@Autowired(required = false)
	private List<AnnotatedParameterProcessor> parameterProcessors = new ArrayList<>();

	@Autowired(required = false)
	private List<FeignFormatterRegistrar> feignFormatterRegistrars = new ArrayList<>();

	@Autowired(required = false)
	private Logger logger;

	@Bean
	@ConditionalOnMissingBean
	public Decoder feignDecoder() {
		return new OptionalDecoder(new ResponseEntityDecoder(new SpringDecoder(this.messageConverters)));
	}

	@Bean
	@ConditionalOnMissingBean
	@ConditionalOnMissingClass("org.springframework.data.domain.Pageable")
	public Encoder feignEncoder() {
		return new SpringEncoder(this.messageConverters);
	}

	@Bean
	@ConditionalOnMissingBean
	public Contract feignContract(ConversionService feignConversionService) {
		return new SpringMvcContract(this.parameterProcessors, feignConversionService);
	}

	@Bean
	@Scope("prototype")
	@ConditionalOnMissingBean
	public Feign.Builder feignBuilder(Retryer retryer) {
		return Feign.builder().retryer(retryer);
	}
}

Feign请求拦截器

参考FeignClientsConfiguration类,我们可以编写一个configuration类,注入自定义的RequestInterceptor实现类对象,在apply(RequestTemplate requestTemplate)方法中获取到请求RestTemplate对象,使用RequestTemplate对象设置请求参数、添加请求头。

示例如下:

@Configuration
public class MyConfig {
	@Bean("myInterceptor")
	public RequestInterceptor getRequestInterceptor() {
		return new MyClientInterceptor();
	}
}

MyClientInterceptor类:

class MyClientInterceptor implements RequestInterceptor {
	@Override
	public void apply(RequestTemplate requestTemplate) {
		requestTemplate.query("name", "Allen");
		requestTemplate
              .header("token", "token")
              .header("id", id);
	}
}

Feign解码器

解码器概述

Feign解码器负责对响应进行解码,返回符合Feign接口需求的对象。

我们可以参考FeignClientsConfiguration类中的方式编写和注入自定义的解码器。

@Bean
@ConditionalOnMissingBean
public Decoder feignDecoder() {
	return new OptionalDecoder(
			new ResponseEntityDecoder(new SpringDecoder(this.messageConverters)));
}

继承SpringDecoder自定义解码器

class TraceDecoder extends SpringDecoder {

	TraceDecoder(ObjectFactory<HttpMessageConverters> messageConverters) {
		super(messageConverters);
	}

	@Override
	public Object decode(Response response, Type type) throws IOException, FeignException {

		// 这里可以从response对象里面获取响应头和响应体

        // 获取响应头
		Map<String, Collection<String>> headers = response.headers();

		return super.decode(response, type);
	}
}

注入自定义解码器

feignDecoder()方法完全参考了FeignClientsConfiguration类的写法。

@Slf4j
@Configuration
@ConditionalOnClass({Feign.class})
@AutoConfigureBefore(FeignAutoConfiguration.class)
public class CommonLogFeignConfig {

	@Autowired
    private ObjectFactory<HttpMessageConverters> messageConverters;

	@Bean
	public Decoder feignDecoder() {
		return new OptionalDecoder(new ResponseEntityDecoder(new TraceDecoder(this.messageConverters)));
	}
}
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在使用 Feign 进行服务间的 HTTP 调用时,你可以通过实现 Feign 的 `RequestInterceptor` 接口来拦截请求的前后方法。`RequestInterceptor` 接口提供了两个方法:`apply()` 和 `decode()`,分别用于请求拦截和响应解码。 下面是一个示例,演示如何在 Feign 请求前后拦截方法: ```java import feign.RequestInterceptor; import feign.RequestTemplate; import feign.Response; import feign.Util; import feign.codec.Decoder; import feign.codec.ErrorDecoder; public class FeignInterceptor implements RequestInterceptor, Decoder, ErrorDecoder { @Override public void apply(RequestTemplate template) { // 在请求前进行拦截的逻辑 // 可以修改请求头、添加认证信息等 } @Override public Object decode(Response response, Type type) throws IOException { // 在响应解码时进行拦截的逻辑 // 可以对响应进行处理、错误处理等 // 这里示例直接使用默认的 Decoder 进行解码 return Util.ensureClosed(response.body().asInputStream(), type); } @Override public Exception decode(String methodKey, Response response) { // 处理 Feign 的错误响应 // 可以根据响应状态码进行自定义异常处理 return FeignException.errorStatus(methodKey, response); } } ``` 上述代码中,`FeignInterceptor` 类实现了 `RequestInterceptor`、`Decoder` 和 `ErrorDecoder` 接口,分别用于请求拦截、响应解码和错误处理。你可以根据实际需求在相应的方法中编写自己的拦截逻辑。 接下来,在使用 Feign 进行服务调用时,需要将自定义的拦截器配置到 Feign 的客户端中: ```java import org.springframework.cloud.openfeign.FeignClient; import org.springframework.context.annotation.Bean; @FeignClient(name = "myService", url = "http://localhost:8080") public interface MyFeignClient { // Feign Client 方法定义 // ... @Configuration class MyFeignConfiguration { @Bean public FeignInterceptor feignInterceptor() { return new FeignInterceptor(); } } } ``` 在上述代码片段中,`MyFeignClient` 是一个使用了 Feign 的客户端接口。通过在配置类中创建 `FeignInterceptor` 实例并将其注册为 Bean,Feign 将会自动使用该拦截器来拦截请求。 通过实现 `RequestInterceptor` 接口并配置到 Feign 客户端中,你可以在 Feign 请求前后进行相应的拦截操作,例如修改请求头、添加认证信息、对响应进行处理等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值