Feign如何使用protobuf的类作为参数调用

目录
  • feign客户端接口定义如下
  • 服务端接口实现如下
  • 在feign接口调用时
  • feign客户端增加一个配置如下
  • 服务端增加一个配置如下
  • 不要加入版本

这两天在把原来的项目迁移到spring cloud上,微服务之间的数据传输使用protobuf。

码了几天的代码。重要准备上线测试下微服务之间的接口调用功能,但是在用feign调用数据库代理接口时,总是报一个错误,在这记录下。

feign客户端接口定义如下

@FeignClient(name = "db-proxy")
public interface RemoteRestFull {
    @RequestMapping(value = "/getUser")
    User.UserInfoRsp getUserInfo(@RequestBody User.UserInfoReq req);
}

服务端接口实现如下

@RestController
public class UserRestFull {
    @RequestMapping("/getUser")
    public User.UserInfoRsp getUserInfo(@RequestBody User.UserInfoReq req) {
        .......
    }
}

服务端具体代码实现就省略了。

服务启动后,使用测试代码测试连接,发送消息。

在feign接口调用时

出现下面的错误:

因为涉及到具体的类报错,省略了一些信息。。。

[WARN ][2021-01-04 14:10:38][DefaultChannelPipeline.java:1152]:onUnhandledInboundException - An exceptionCaught() event was fired, and it reached at the tail of the pipeline. It usually means the last handler in the pipeline did not handle the exception.
feign.codec.EncodeException: Error converting request body
        at org.springframework.cloud.openfeign.support.SpringEncoder.encode(SpringEncoder.java:119) ~[spring-cloud-openfeign-core-2.2.5.RELEASE.jar!/:2.2.5.RELEASE]
        at org.springframework.cloud.openfeign.support.PageableSpringEncoder.encode(PageableSpringEncoder.java:101) ~[spring-cloud-openfeign-core-2.2.5.RELEASE.jar!/:2.2.5.RELEASE]
        at feign.ReflectiveFeign$BuildEncodedTemplateFromArgs.resolve(ReflectiveFeign.java:380) ~[feign-core-10.10.1.jar!/:?]
        at feign.ReflectiveFeign$BuildTemplateByResolvingArgs.create(ReflectiveFeign.java:232) ~[feign-core-10.10.1.jar!/:?]
        at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:84) ~[feign-core-10.10.1.jar!/:?]
        at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:100) ~[feign-core-10.10.1.jar!/:?]
        at com.sun.proxy.$Proxy93.getUser(Unknown Source) ~[?:?]
        ......................
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:324) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:296) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.handler.logging.LoggingHandler.channelRead(LoggingHandler.java:271) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.handler.codec.ByteToMessageDecoder.handlerRemoved(ByteToMessageDecoder.java:253) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:508) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:440) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:276) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.handler.logging.LoggingHandler.channelRead(LoggingHandler.java:271) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:719) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:655) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:581) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) [netty-all-4.1.54.Final.jar!/:4.1.54.Final]
        at java.lang.Thread.run(Thread.java:748) [?:1.8.0_231]
Caused by: org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class com.google.protobuf.UnknownFieldSet$Parser]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class com.google.protobuf.UnknownFieldSet$Parser and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: cn.nodetec.easychat.proto.IMUser$IMUserLogin["unknownFields"]->com.google.protobuf.UnknownFieldSet["parserForType"])
        at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:348) ~[spring-web-5.2.10.RELEASE.jar!/:5.2.10.RELEASE]
        at org.springframework.http.converter.AbstractGenericHttpMessageConverter.write(AbstractGenericHttpMessageConverter.java:104) ~[spring-web-5.2.10.RELEASE.jar!/:5.2.10.RELEASE]
        at org.springframework.cloud.openfeign.support.SpringEncoder.checkAndWrite(SpringEncoder.java:176) ~[spring-cloud-openfeign-core-2.2.5.RELEASE.jar!/:2.2.5.RELEASE]
        at org.springframework.cloud.openfeign.support.SpringEncoder.encode(SpringEncoder.java:109) ~[spring-cloud-openfeign-core-2.2.5.RELEASE.jar!/:2.2.5.RELEASE]
        ... 46 more
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class com.google.protobuf.UnknownFieldSet$Parser and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: cn.nodetec.easychat.proto.IMUser$IMUserLogin["unknownFields"]->com.google.protobuf.UnknownFieldSet["parserForType"])
        at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77) ~[jackson-databind-2.11.3.jar!/:2.11.3]
        at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1277) ~[jackson-databind-2.11.3.jar!/:2.11.3]
        at com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:400) ~[jackson-databind-2.11.3.jar!/:2.11.3]
        at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.failForEmpty(UnknownSerializer.java:71) ~[jackson-databind-2.11.3.jar!/:2.11.3]
        at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.serialize(UnknownSerializer.java:33) ~[jackson-databind-2.11.3.jar!/:2.11.3]
        at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728) ~[jackson-databind-2.11.3.jar!/:2.11.3]
        at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:755) ~[jackson-databind-2.11.3.jar!/:2.11.3]
        at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178) ~[jackson-databind-2.11.3.jar!/:2.11.3]
        at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728) ~[jackson-databind-2.11.3.jar!/:2.11.3]
        at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:755) ~[jackson-databind-2.11.3.jar!/:2.11.3]
        at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178) ~[jackson-databind-2.11.3.jar!/:2.11.3]
        at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480) ~[jackson-databind-2.11.3.jar!/:2.11.3]
        at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319) ~[jackson-databind-2.11.3.jar!/:2.11.3]
        at com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize(ObjectWriter.java:1516) ~[jackson-databind-2.11.3.jar!/:2.11.3]
        at com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:1006) ~[jackson-databind-2.11.3.jar!/:2.11.3]
        at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:342) ~[spring-web-5.2.10.RELEASE.jar!/:5.2.10.RELEASE]
        at org.springframework.http.converter.AbstractGenericHttpMessageConverter.write(AbstractGenericHttpMessageConverter.java:104) ~[spring-web-5.2.10.RELEASE.jar!/:5.2.10.RELEASE]
        at org.springframework.cloud.openfeign.support.SpringEncoder.checkAndWrite(SpringEncoder.java:176) ~[spring-cloud-openfeign-core-2.2.5.RELEASE.jar!/:2.2.5.RELEASE]
        at org.springframework.cloud.openfeign.support.SpringEncoder.encode(SpringEncoder.java:109) ~[spring-cloud-openfeign-core-2.2.5.RELEASE.jar!/:2.2.5.RELEASE]
        ... 46 more

从log看,是AbstractJackson2HttpMessageConverter转换的问题,感谢度娘。让我找到了下面的解决方法。

这个问题主要是因为,feign的参数使用protobuf的类,在转换的时候,找不到Converter,如果是使用基本的数据类型是没有任何问题的。

所以,我们需要配置一个protobuf的HttpMessageConverter。

feign客户端增加一个配置如下

import feign.codec.Decoder;
import feign.codec.Encoder;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.openfeign.support.ResponseEntityDecoder;
import org.springframework.cloud.openfeign.support.SpringDecoder;
import org.springframework.cloud.openfeign.support.SpringEncoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter;
 
@Configuration
public class ProtoFeignConfig {
    @Autowired
    private ObjectFactory<HttpMessageConverters> messageConverterObjectFactory;
 
    @Bean
    public ProtobufHttpMessageConverter protobufHttpMessageConverter() {
        return new ProtobufHttpMessageConverter();
    }
 
    @Bean
    public Encoder springEncoder() {
        return new SpringEncoder(this.messageConverterObjectFactory);
    }
 
    @Bean
    public Decoder springDecoder() {
        return new ResponseEntityDecoder(new SpringDecoder(this.messageConverterObjectFactory));
    }
}

服务端增加一个配置如下

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter;
 
@Configuration
public class ProtoFeignConfig {
    @Bean
    public ProtobufHttpMessageConverter protobufHttpMessageConverter() {
        return new ProtobufHttpMessageConverter();
    }
}

当然,pom中使用的是openfeign,依赖如下,注意

不要加入版本

否则编译报错:

<dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

这样就可以正常调用了。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • SpringCloud使用Feign实现服务调用

    Spring Cloud Feign简介 Spring Cloud Feign也是一个基础工具类,它整合了Spring Cloud Ribbon和Spring Cloud Hystrix,除了提供这两者的强大功能以外,它还提供了一种声明式的Web服务客户端定义方式.使用它可以进行服务的消费,但是它的客户端负载平衡仍是通过Ribbon实现的 使用Spring Cloud Feign 创建一个SpringBoot工程,作为服务调用方 1.pom.xml <dependency> <group

  • SpringBoot使用protobuf格式的接口方式

    SpringBoot使用protobuf格式的接口 建立SpringBoot项目,pom.xml内容如下: <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:sche

  • Protobuf的简要介绍及使用详解

    一.protobuf的应用场景 在官方文档中可以看到 protocol buffers 是一种语言无关.平台无关.可扩展的序列化结构数据的方法,它可用于(数据)通信协议.数据存储等. Protocol Buffers 是一种灵活,高效,自动化机制的结构数据序列化方法-可类比 XML,但是比 XML 更小(3 ~ 10倍).更快(20 ~ 100倍).更为简单. 可以看到protobuf 与json相比具有 压缩比高 .解压缩速度更快的优点 二.protobuf的使用 protobuf在使用上较为

  • Spring Cloud Feign简单使用详解

    概述 在Spring Cloud EureKa Ribbon 服务注册-发现-调用一文中简单的介绍了在Spring Cloud中如何使用EureKa和Ribbon.文章中使用了RestTemplate去访问其他的restful微服务接口.其实在Spring Cloud还可以使用Feign来访问其他的restful微服务接口.使用起来更加的简洁明了. 集成Feign 修改一下Spring Cloud EureKa Ribbon 服务注册-发现-调用中order service的pom配置,把Feg

  • Feign如何使用protobuf的类作为参数调用

    目录 feign客户端接口定义如下 服务端接口实现如下 在feign接口调用时 feign客户端增加一个配置如下 服务端增加一个配置如下 不要加入版本 这两天在把原来的项目迁移到spring cloud上,微服务之间的数据传输使用protobuf. 码了几天的代码.重要准备上线测试下微服务之间的接口调用功能,但是在用feign调用数据库代理接口时,总是报一个错误,在这记录下. feign客户端接口定义如下 @FeignClient(name = "db-proxy") public i

  • 解决springmvc关于前台日期作为实体类对象参数类型转换错误的问题

    页面报错: 后台错误: Field error in object 'user' on field 'birthday': rejected value [2013-06-24]; codes [typeMismatch.user.birthday,typeMismatch.birthday,typeMismatch.java.util.Date,typeMismatch]; arguments [org.springframework.context.support.DefaultMessag

  • java根据不同的参数调用不同的实现类操作

    本猿今天今天帮公司写第三支付接口的时候,灵机一动就想写一个扩展性比较的强的充值接口,t通过选择不同的充值渠道,调用不同的充值实现类(好了,废话不多说了,上码!!!!!) 首先你得写一个接口(楼主用的框架是springMVC +Spring +嘿嘿)PayService 然后写你的PayService实现类 EcpssPayService(第三方接口实现类)和 ReapalPayService(第三方接口实现类) 注意几点(注解一定得跟上) 好了之后 就可以 写一个工具类了 SpringBeanU

  • 解决SpringCloud Feign传对象参数调用失败的问题

    SpringCloud Feign传对象参数调用失败 不支持GET请求方式 使用Apache HttpClient替换Feign原生httpclient @RequestBody接收json参数 bootstrap-local.yml feign: httpclient: enabled: true pom.xml <!-- 使用Apache HttpClient替换Feign原生httpclient --> <dependency> <groupId>com.netf

  • Mybatis传list参数调用oracle存储过程的解决方法

    怎么利用MyBatis传List类型参数到数据库存储过程中实现批量插入数据? MyBatis中参数是List类型时怎么处理?大家都知道MyBatis批处理大量数据是很难做到事务回滚的(事务由Spring管理),都将逻辑写在存储中又是及其头疼的一件事(参数长度也有限制),那么我想的是将参数在后台封装为单个或多个list集合,直接通过MyBatis将此参数传到数据库存储过程中,一来摆脱了MyBatis批量插入数据的诸多限制(例如:不能实时返回主键.foreach标签循环集合长度有限制),二来就是在存

  • Python自定义函数定义,参数,调用代码解析

    函数能提高应用的模块性,和代码的重复利用率.Python提供了许多内建函数,比如print()等.也可以创建用户自定义函数. 函数定义 函数定义的简单规则: 函数代码块以def关键词开头,后接函数标识符名称和圆括号(),任何传入参数和自变量必须放在圆括号中间 函数内容以冒号起始,并且缩进 若有返回值,Return[expression]结束函数:不带return表达式相当于返回None 函数通常使用三个单引号'''...'''来注释说明函数:函数体内容不可为空,可用pass来表示空语句:以下几个

  • javascript中函数作为参数调用的方法

    本文实例讲述了javascript中函数作为参数调用的方法.分享给大家供大家参考.具体分析如下: 先来看示例: function Map(){ var obj = {}; this.put = function(key, value){ obj[key] = value; } this.eachMap = function(fn){ for(var attr in obj){ fn(attr, obj[attr]); } } } var m = new Map(); m.put('01', 'a

  • PHP验证码类文件及调用方式代码详解

    代码如下所示: //验证码类 class ValidateCode { private $charset = 'abcdefghkmnprstuvwxyzABCDEFGHKMNPRSTUVWXYZ23456789';//随机因子 private $code;//验证码 private $codelen = 4;//验证码长度 private $width = 130;//宽度 private $height = 50;//高度 private $img;//图形资源句柄 private $fon

  • thinkPHP5.1框架中Request类四种调用方式示例

    本文实例讲述了thinkPHP5.1框架中Request类四种调用方式.分享给大家供大家参考,具体如下: 1. 传统调用 访问方式:http://127.0.0.1/demo/demo3/test?name=kk&age=22 <?php /** * Created by PhpStorm. * User: 10475 * Date: 2018/8/27 * Time: 22:59 */ namespace app\demo\controller; use think\Request; cl

  • Python中函数参数调用方式分析

    本文实例讲述了Python中函数参数调用方式.分享给大家供大家参考,具体如下: Python中函数的参数是很灵活的,下面分四种情况进行说明. (1) fun(arg1, arg2, ...) 这是最常见的方式,也是和其它语言类似的方式 下面是一个实例: >>> def fun(x, y): return x - y >>> fun(12, -2) 14 (2) fun(arg1, arg2=value2, ...) 这种就是所谓的带默认参数的函数,调用的时候我们可以指定

随机推荐