【问题标题】:Feign Error Decoder with custom JSON response带有自定义 JSON 响应的 Feign 错误解码器
【发布时间】:2020-11-14 00:35:40
【问题描述】:

我有一个 API,它将以自定义响应消息的形式返回失败,同时仍发送 Http 200 响应。示例:

Status: 200
Body: {
   "code":404,
   "message":"Data not found",
   "data":{},
   "status":"ERROR"
}

我当前的 ErrorDecoder 实现:

public class ApiFeignErrorDecoder implements ErrorDecoder {

    private final Gson gson;

    public ApiFeignErrorDecoder(Gson gson) {
        this.gson = gson;
    }

    @Override
    public Exception decode(String methodKey, Response response) {

        try {
            ApiResponse apiResponse = gson.fromJson(response.body().asReader(), BaseApiResponse.class);
            ResponseStatus status = apiResponse.getStatus();
            switch (status) {
                case SUCCESS:
                    return null;
                case FAIL:
                    return new Exception("Failure message recorded");
                case ERROR:
                    return new Exception("Error message recorded");
                default:
                    return new Exception("No suitable status found.");
            }
        } catch (IOException e) {
            e.printStackTrace();
            return new ErrorDecoder.Default().decode(methodKey, response);
        }
    }

}

我遇到的问题是,如果 HttpStatus > 300,Feign/Spring 只会切换到 ErrorDecoder。错误解码器中的 JavaDocs 也描述了这个限制:

“错误处理 Response.status() 不在 2xx 范围内的响应被归类为错误,由 ErrorDecoder 解决。也就是说,某些 RPC API 即使在 200 状态下也会返回 Response.body() 中定义的错误. 例如,在 DynECT api 中,作业仍在运行状态返回 200 状态,以 json 编码。当发生此类情况时,您应该引发特定于应用程序的异常(可能是可重试的)。”

我现在的问题是什么/如何实现这些,或者有没有办法扩展 ErrorDecoder 以使我能够处理这些错误消息。我想我应该能够将它们放入解码器甚至实现/覆盖 HttpClient,但我不确定正确/最好的方法是什么。

【问题讨论】:

    标签: spring-boot spring-cloud-feign feign


    【解决方案1】:

    ErrorDecoder 一样,您可以使用SpringDecoder 编写自定义逻辑来处理成功响应。

    private class ResponseDecoder extends SpringDecoder {
    
        public ResponseDecoder(ObjectFactory<HttpMessageConverters> messageConverters) {
            super(messageConverters);
        }
    
        @Override
        public Object decode(Response response, Type type) throws IOException, FeignException {
            try {
                ApiResponse apiResponse = gson.fromJson(response.body().asReader(), BaseApiResponse.class);
                ResponseStatus status = apiResponse.getStatus();
                switch (status) {
                    case SUCCESS:
                        return null;
                    case FAIL:
                        throw new FeignException(FAIL, "Failure message recorded");
                    case ERROR:
                        throw new FeignException(ERROR, "Error message recorded");
                    default:
                        throw new FeignException(YOUR_DEFAULT_ERROR_CODE, "No suitable status found.");
                }
            } catch (IOException e) {
                e.printStackTrace();
                return null; // return accordingly to your use-case
            }
        }
    
    }
    

    Feign 客户端接口:

    @FeignClient(value = "foo", configuration = FooClientConfig.class)
    public interface FooClient {
        //Your mappings
    }
    

    Feign 客户端自定义配置:

    @Configuration
    public class FooClientConfig {
    
        @Bean
        public Decoder feignDecoder() {
            // if you're using gson, add gson converter here instead
            HttpMessageConverter jacksonConverter = new MappingJackson2HttpMessageConverter(customObjectMapper());
            ObjectFactory<HttpMessageConverters> objectFactory = () -> new HttpMessageConverters(jacksonConverter);
            return new ResponseEntityDecoder(new ResponseDecoder(objectFactory));
        }
    
        public ObjectMapper customObjectMapper(){
            ObjectMapper objectMapper = new ObjectMapper();
            //Customize as much as you want
            return objectMapper;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2020-09-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-25
      • 2018-02-12
      • 2020-05-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多