在GateWay通过FeignClient调用Auth模块的方法出错。
先上错误,然后是源码,最后是结论:
feign.codec.EncodeException: No qualifying bean of type 'org.springframework.boot.autoconfigure.http.HttpMessageConverters' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at feign.ReflectiveFeign$BuildEncodedTemplateFromArgs.resolve(ReflectiveFeign.java:384) ~[feign-core-10.7.4.jar:na]
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Error has been observed at the following site(s):
|_ checkpoint ⇢ org.springframework.cloud.gateway.filter.WeightCalculatorWebFilter [DefaultWebFilterChain]
|_ checkpoint ⇢ HTTP POST "/usercenter/login/test" [ExceptionHandlingWebHandler]
Stack trace:
at feign.ReflectiveFeign$BuildEncodedTemplateFromArgs.resolve(ReflectiveFeign.java:384) ~[feign-core-10.7.4.jar:na]
at feign.ReflectiveFeign$BuildTemplateByResolvingArgs.create(ReflectiveFeign.java:232) ~[feign-core-10.7.4.jar:na]
at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:75) ~[feign-core-10.7.4.jar:na]
public class JsonResult implements Serializable {
private final long SERIALIZABLE_ID = 1<<31L;
private int status;
private boolean success;
private String message;
private Object result;
private JsonResult(){
status=200;
success=true;
message=null;
result=null;
}
/*------------一些方法------------*/
/*------------Getter&Setter实现------------*/
}
public class User implements Serializable {
private final static long SERIALIZABLE_ID=1<<31L;
private String id;
private String pwd;
private String token;
private String path;
private String ip;
/*------Getter&Setter实现-----*/
}
@RestController
@RequestMapping("token")
@CrossOrigin("*")
public class AuthApi {
@Autowired
AuthController authController;
/**
* @decription 验证用户token及资源权限
* @param user
* @return JsonResult
*/
@RequestMapping("/check")
public JsonResult checkToken(@RequestBody User user){
return authController.checkToken(user);
}
}
@Service
@FeignClient(value = "auth",configuration = FeignConfig.class)
public interface AuthFeignApi {
@RequestMapping(value = "/token/check",method = {RequestMethod.POST})
JsonResult checkToken(@RequestBody User user);
}
@Configuration
public class FeignConfig {
@Autowired
private ObjectFactory<HttpMessageConverters> messageConverters;
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
//feign拦截器,设置header信息
@Bean
FeignInterceptor feignInterceptor() {
return new FeignInterceptor();
}
@Bean
public Decoder feignDecoder() {
return new ResponseEntityDecoder(new SpringDecoder(feignHttpMessageConverter()));
}
public ObjectFactory<HttpMessageConverters> feignHttpMessageConverter() {
final HttpMessageConverters httpMessageConverters = new HttpMessageConverters(new GateWayMappingJackson2HttpMessageConverter());
return new ObjectFactory<HttpMessageConverters>() {
@Override
public HttpMessageConverters getObject() throws BeansException {
return httpMessageConverters;
}
};
}
public class GateWayMappingJackson2HttpMessageConverter extends MappingJackson2HttpMessageConverter {
GateWayMappingJackson2HttpMessageConverter(){
List<MediaType> mediaTypes = new ArrayList<>();
mediaTypes.add(MediaType.valueOf(MediaType.TEXT_HTML_VALUE + ";charset=UTF-8"));
mediaTypes.add(MediaType.valueOf(MediaType.APPLICATION_JSON_VALUE + ";charset=UTF-8"));
setSupportedMediaTypes(mediaTypes);
}
}
}
public class FeignInterceptor {
public void apply(RequestTemplate requestTemplate) {
requestTemplate.header("Access-Control-Allow-Origin", "*")
.header("Content-Type","application/json");
}
}
@Controller
public class AuthenticationFitler implements GlobalFilter, Ordered {
@Autowired(required = true)
AuthFeignApi authFeignApi;
/**
* 拦截器,校验
* @param exchange
* @param chain
* @return
*/
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// exchange.getRequest().getHeaders().set("Access-Control-Allow-Origin","*");
String token = exchange.getRequest().getHeaders().getFirst("token");
String id = exchange.getRequest().getHeaders().getFirst("id");
String pwd = exchange.getRequest().getHeaders().getFirst("pwd");
String path = exchange.getRequest().getPath().toString();
//是否为白名单
if(WhiteListFilter.isWhiteUser(id)||WhiteListFilter.isWhiteResources(path))
return chain.filter(exchange);
//token校验
User user = new User();
user.setToken(token);
user.setId(id);
user.setPwd(pwd);
JsonResult result = authFeignApi.checkToken(user); //此处
if(!result.isSuccess()){
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
//用户-资源权限校验
return chain.filter(exchange);
}
}
手动注入就可以了
@Bean
@ConditionalOnMissingBean
public HttpMessageConverters messageConverters(ObjectProvider<HttpMessageConverter<?>> converters) {
return new HttpMessageConverters(converters.orderedStream().collect(Collectors.toList()));
}
大哥厉害!
楼主的错误看着像是spring没法找到接口实现导致的,我看你的feign接口上加了@Service,可以去掉试试,@FeignClient一个注解就够了,在入口类上别忘启动@EnableFeignClients
去掉了@Service注解也不行.......