如何在调用ErrorDecoder之前拦截伪装和 Spring Boot 中的http响应

doinxwow  于 2022-12-04  发布在  Spring
关注(0)|答案(2)|浏览(124)

我需要拦截HTTP响应并更改HTTP状态代码。例如,我可能会将200更改为400(基于响应对象本身),以便调用ErrorDecoder。
我需要在不扩展feign.Client类的情况下执行此操作!(实际上,我使用的feign.httpclient.ApacheHttpClient是final!)
我试图为ResponseMapper提供一个实现,但似乎只有在AsyncResponseHandler#handleResponse内部完成HTTP状态检查后,才能调用响应Map器(以及我用来覆盖的Decoder)!
我在这里主要讨论SynchronousMethodHandlerAsyncResponseHandler的实现方式。

总结一下,我的主要问题是AsyncResponseHandler#handleResponseErrorDecoder之前没有调用Decoder(因此是ResponseMapper),如果它调用了Decoder,那么ResponseMapper可以执行我需要的HTTP状态代码。

46scxncf

46scxncf1#

为了克服这个缺点,我将引用代码中的实现类(而不是依赖于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 {

    // ...
}
bnl4lu3b

bnl4lu3b2#

SynchronousMethodHandler使用feign.Logger打印假装请求过程前后的日志,除非日志级别为NONE,调用顺序如下:

  1. logger.logResuest(configKey, logLevel, request)
  2. response = client.execute(request, options)
  3. response = logger.logAndRebufferResponse(configKey, logLevel, response, elapsedTime)
    此记录器是由**DefaultFeignLoggerFactory#create()**创建的。如果您定义自己的记录器并将其注册为SringBean,DefaultFeignLoggerFactory应使用自己的记录器来打印日志,您可以在FeignClientsConfigurations中看到记录器为@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();
    }
}

这很管用。

相关问题