【问题标题】:How to intercept http response in feign and spring boot before ErrorDecoder invoked如何在调用 ErrorDecoder 之前拦截 feign 和 spring boot 中的 http 响应
【发布时间】:2022-11-30 10:24:31
【问题描述】:

我需要拦截 HTTP 响应并更改 HTTP 状态代码。 例如,我可能会将 200 更改为 400(基于响应对象本身)以便调用 ErrorDecoder。

我需要在不扩展 feign.Client 类的情况下执行此操作! (事实上​​,我使用的 feign.httpclient.ApacheHttpClient 是最终的!)

我试图为 ResponseMapper 提供一个实现,但似乎只有在 AsyncResponseHandler#handleResponse 内部完成 HTTP 状态检查后才会调用响应映射器(以及我用来覆盖的 Decoder)!

我在这里主要谈论SynchronousMethodHandlerAsyncResponseHandler的实现是如何工作的。

把它们加起来,我的主要问题是 AsyncResponseHandler#handleResponse 不会在 ErrorDecoder 之前调用 Decoder(因此调用 ResponseMapper),如果调用了,那么 ResponseMapper 可以执行我需要的 HTTP 状态代码。

【问题讨论】:

    标签: java spring-boot feign


    【解决方案1】:

    为了克服这个缺点,Id在代码中引用实现类(而不是依赖于spring boot的自动配置)

    @Bean
    public Client feignClient(HttpClient httpClient) {
        var client = new ApacheHttpClient(httpClient);
        return (request, options) -> convertResponse(client.execute(request, options));
    }
    
    private Response convertResponse(Response response) throws IOException {
    
        // ...
    }
        
    

    【讨论】:

      【解决方案2】:

      同步方法处理器使用假装记录器除非日志级别为 NONE,否则在假请求过程之前和之后打印日志。调用顺序如下:

      1. logger.logResuest(configKey, logLevel, request)
      2. response = client.execute(request, options)
      3. response = logger.logAndRebufferResponse(configKey, logLevel, response, elapsedTime)

        这个记录器是由默认FeignLoggerFactory#create().如果您定义自己的记录器并将其注册为 SringBean,DefaultFeignLoggerFactory应该使用自己的logger来打印日志,在FeignClientsConfigurations可以看到logger是@Autowired(required = false)。 所以你应该定义自己的记录器,例如:

        public class MyFeignLogger extends Slf4jLogger {
        
            @Override
            protected Response logAndRebufferResponse(String configKey, Logger.Level logLevel, Response response, long elapsedTime) {
                Response rsp = super.logAndRebufferResponse(configKey, logLevel, response, elapsedTime);
                //you can change response status here by java reflect. 
                if(xxxx) {
                    ReflectUtil.setFieldValue(rsp, "status", 400);
                }
                return rsp;
            }
        }
        

        然后将这个类注册为Bean:

        @Configuration
        @AutoConfiguration(FeignClientsConfiguration.class)
        public class MyFeignConfiguration {
        
            @Bean
            @Primary
            public Logger.Level feignLoggerLevel() {
                return Logger.Level.FULL;
            }
        
            @Bean
            @Primary
            public Logger feignLogger() {
                return new MyFeignLogger();
            }
        }
        

        有用。

      【讨论】:

        猜你喜欢
        • 2019-06-12
        • 2020-01-21
        • 2015-10-21
        • 2016-02-02
        • 1970-01-01
        • 1970-01-01
        • 2018-10-29
        • 2020-10-08
        • 1970-01-01
        相关资源
        最近更新 更多