【问题标题】:Feign encoder/decoder for Google Protocol Buffers用于 Google 协议缓冲区的 Feign 编码器/解码器
【发布时间】:2021-02-16 09:30:41
【问题描述】:

我使用Feign 作为 HTTP 客户端。现在我面临一个使用Google Protobuf 的API。 Feign 没有为 Protobuf 提供任何编码器/解码器,因此需要实现自定义。

import feign.RequestTemplate
import feign.codec.EncodeException
import feign.codec.Encoder

import java.lang.reflect.Type

class ProtobufEncoder implements Encoder {

    @Override
    void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException {
         // I am stuck here
    }
    
}

以前有人解决过这个问题吗?

更新:我正在寻找一种在没有 Spring 的情况下使用普通 Feign 的解决方案。

【问题讨论】:

    标签: java groovy protocol-buffers feign


    【解决方案1】:

    实现 protobuf 编码(在 this GitHub issue 中描述)的一种方法是使用 ProtobufHttpMessageConverter 类和来自 spring-cloud-openfeign 库的 SpringEncoder \ SpringDecoder。 在您的应用程序中,您需要配置 bean:

    import org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter;
    
    @Configuration
    public class ProtoBufConfig {
        @Autowired
        private ObjectFactory<HttpMessageConverters> messageConverters;
        
        @Bean
        ProtobufHttpMessageConverter protobufHttpMessageConverter() {
            return new ProtobufHttpMessageConverter();
        }
    
        //override the encoder
        @Bean
        public Encoder springEncoder(){
            return new SpringEncoder(this.messageConverters);
        }
    
        @Bean
        public Decoder springDecoder(){
            return new ResponseEntityDecoder(new SpringDecoder(this.messageConverters));
        }
    }
    

    你可以在FeignClient注解中使用这个配置:

    @FeignClient(name = "example-svc", configuration=ProtoBufConfig.class)
    public interface KittensApiResource {
    
        @RequestMapping(value="/v1/api/kittens", method = RequestMethod.GET, consumes="application/x-protobuf", produces="application/x-protobuf")
        public ResponseEntity<KittenResponse> kittens();
    }
    

    【讨论】:

    • 感谢您的回答。我想这种方式只有在有人使用 Spring Framework 时才有效。
    【解决方案2】:

    这就是我想出的。我还必须使用 Base64 进行编码/解码,因为我正在使用的 API 需要它。

    解码器:

    @Slf4j
    class ProtobufBase64Decoder implements Decoder {
    
        Map<Type, Message> protoMessagesCache = new HashMap<>()
    
        @Override
        Object decode(Response response, Type type) throws IOException, DecodeException, FeignException {
            if (response.body() == null) {
                return null
            }
            InputStream inputStream = BaseEncoding.base64().decodingStream(response.body().asReader(Charset.defaultCharset()))
            Message message = computeMessageForType(type)
            message.toBuilder().mergeFrom(inputStream).build()
        }
    
        private Message computeMessageForType(Type type) {
            if (!protoMessagesCache.containsKey(type)) {
                    if (Message.class.isAssignableFrom(type)) {
                        Method builderMethod = type.getMethod("newBuilder")
                        Message message = ((Message.Builder) builderMethod.invoke(type)).getDefaultInstanceForType()
                        protoMessagesCache.put(type, message)
                    } else {
                        throw new NoClassDefFoundError()
                    }
            }
            protoMessagesCache.get(type)
        }
    
    }
    

    编码器:

    @Slf4j
    class ProtobufBase64Encoder implements Encoder {
    
        @Override
        void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException {
            try {
                Message message = Message.cast(object)
                template.body(BaseEncoding.base64().encode(message.toByteArray()))
            } catch (ClassCastException ignored) {
                log.error("Unable to encode {} into protobuf", object)
            }
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-02-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多