如何在Feign与Spring Boot中ErrorDecoder执行前拦截HTTP响应
解决Feign修改响应状态码触发ErrorDecoder的问题
可行方案:Client装饰器模式(无需继承final类)
由于feign.httpclient.ApacheHttpClient是final类无法继承,我们可以用装饰器模式包装原Client实例,在响应返回给Feign核心逻辑前修改状态码,这样后续的错误检查流程会直接识别修改后的状态码并触发ErrorDecoder。
1. 实现包装类
创建实现feign.Client接口的包装类,内部持有原ApacheHttpClient实例,在execute方法中拦截响应并修改状态码:
public class ResponseStatusModifyingClient implements feign.Client { private final feign.Client delegateClient; public ResponseStatusModifyingClient(feign.Client delegate) { this.delegateClient = delegate; } @Override public Response execute(Request request, Options options) throws IOException { // 调用原Client获取响应 Response originalResponse = delegateClient.execute(request, options); // 自定义逻辑:判断是否需要修改状态码(示例:将特定200响应改为400) if (shouldModifyStatus(originalResponse)) { // 构造新的响应对象,替换状态码 return Response.builder() .status(400) .headers(originalResponse.headers()) .body(originalResponse.body(), originalResponse.charset()) .request(originalResponse.request()) .build(); } return originalResponse; } // 自定义判断逻辑:根据响应内容、请求路径等决定是否修改状态码 private boolean shouldModifyStatus(Response response) { return response.status() == 200 && response.request().url().contains("/specific-path") /* 其他业务条件 */; } }
2. 配置Feign客户端
构建Feign客户端时,将包装后的Client传入:
// 创建原ApacheHttpClient实例 ApacheHttpClient originalHttpClient = new ApacheHttpClient(); // 包装成自定义Client ResponseStatusModifyingClient modifiedClient = new ResponseStatusModifyingClient(originalHttpClient); // 构建Feign客户端 MyFeignApi feignClient = Feign.builder() .client(modifiedClient) .errorDecoder(new CustomErrorDecoder()) // 你的自定义ErrorDecoder // 其他配置:Decoder、Encoder等 .target(MyFeignApi.class, "http://your-api-host");
为什么ResponseMapper方案无效?
Feign默认的AsyncResponseHandler#handleResponse执行顺序是:
- 先检查响应状态码是否属于错误范围(4xx/5xx)
- 若是错误状态码,直接调用ErrorDecoder处理
- 若为正常状态码,才调用Decoder及关联的ResponseMapper
这就导致ResponseMapper的状态码修改发生在错误检查之后,无法触发ErrorDecoder。而装饰器方案在Feign核心逻辑处理响应前就修改了状态码,让后续流程直接识别为错误状态,自然会触发ErrorDecoder。
内容的提问来源于stack exchange,提问作者Muhammad Hewedy
相关产品推荐
相关产品推荐

