上次成功把项目打包以后,运行也正常,但是在一个openFeign调用的接口里面出现奇怪的现象:
admin模块中我定义的获取当前用户的方法getCurrentUser方法来获取当前用户,contract模块中,我使用openFeign调用该方法,然后获取用户的id来查询,但是页面数据为空,这就很奇怪了。
在idea里面启动项目,查询页面数据一切正常,打断点、debug,也确实获取了当前用户的id。就是打包以后,在运行jar包的情况下,openFeign就调用不到了,查看控制台,里面打印的sql,其中的用户id参数竟然是null。
经过百度:
有的说新版的springgateway与openFeign存在版本兼容问题,spring-cloud-starter-gateway 依赖的是 spring-boot-starter-webflux, 但是 OpenFeign 用的是spring-boot-starter-web。
spring-boot-starter-webflux和spring-boot-starter-web 二者只能选一。
必须使用异步调用FeignClient的方式,不能同步调用,或者使用WebClient,原文地址:
FeignClient异步调用
这个方法我没解决,仅供参考,因为被调用方返回值为用户对象User:
考虑到可能是返回值的问题,调用的返回值没办法被解析?修改接口,使其只返回一个Long类型的id,:
还是报错Cannot deserialize value of type java.lang.Long from Object value (token JsonToken.START_OBJECT)
猜测是openFeign返回的是Object类型对象,没办法把它反序列化成Long类型?
反反复复折腾,还报错406feign.FeignException$NotAcceptable
的错,
查到一个原因:可能是Feign在组装Http请求去调用远端服务时 请求头参数有问题,
解决方法:接口上增加参数:produces = MediaType.APPLICATION_JSON_UTF8_VALUE
,经过测试。这个已经过时,使用新的代替方案:
被调用方作为生产者,增加属性:produces="application/json; charset=UTF-8"
调用方client作为消费者,增加属性:consumes = "application/json; charset=UTF-8"
consumes定义了方法接受的Http的请求类型,produces则定义了Http请求返回的类型。
FeignClient,它的底层实现,就是根据定义的FeignClient,来组装Http请求进行远程调用,
配置完以后,报了新的错:java.lang.NumberFormatException: For input string:
,报错信息里面竟然是401,未登录的错,这就有点迷惑了,本地调用都没问题,打个包部署运行,去调用方法,竟然是未登录状态。
原因在于:springcloud open-feign需要添加、传递请求头:
当我们feign调用提供者需要携带自定义的请求头,或者想继续传递上游服务的请求头信息时,可进行如下方式处理
1、实现RequestInterceptor,并Configuration注解标记为配置类
2、复写apply 方法,将我们的自定义的请求头 通过header存进去即可
3、可根据请求信息遍历请求头信息,选择是否将上游请求头信息向下游服务传递
4、该配置类需要能被扫包扫到(主启动函数 子侄包路径)
这里我使用配置类的方式,新增配置类FeignConfig:
@Configuration
public class FeignConfig implements RequestInterceptor {
@Override
public void apply(RequestTemplate template) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
Enumeration<String> headerNames = request.getHeaderNames();
template.header(headerNames.nextElement(), request.getHeader(headerNames.nextElement()));
if (headerNames == null) {
return;
}
//处理上游请求头信息,传递时继续携带
while (headerNames.hasMoreElements()) {
String name = headerNames.nextElement();
String values = request.getHeader(name);
template.header(name, values);
}
}
}
打包以后,完美调用