Spring Cloud中使用Feign,@RequestBody无法继承的解决方案
Spring Cloud中使用Feign,@RequestBody无法继承的问题
根据官网FeignClient的例子,编写一个简单的updateUser接口,定义如下
@RequestMapping("/user") public interface UserService { @RequestMapping(value = "/{userId}", method = RequestMethod.GET) UserDTO findUserById(@PathVariable("userId") Integer userId); @RequestMapping(value = "/update", method = RequestMethod.POST) boolean updateUser(@RequestBody UserDTO user); }
实现类
@Override public boolean updateUser(UserDTO user) { LOGGER.info("===updateUser, id = " + user.getId() + " ,name= " + user.getUsername()); return false; }
执行单元测试,发现没有获取到预期的输入参数
2018-09-07 15:35:38,558 [http-nio-8091-exec-5] INFO [com.springboot.user.controller.UserController] {} - ===updateUser, id = null ,name= null
原因分析
SpringMVC中使用RequestResponseBodyMethodProcessor类进行入参、出参的解析。以下方法根据参数是否有@RequestBody注解判断是否进行消息体的转换。
@Override public boolean supportsParameter(MethodParameter parameter) { return parameter.hasParameterAnnotation(RequestBody.class); }
解决方案
既然MVC使用RequestResponseBodyMethodProcessor进行参数解析,可以实现一个定制化的Processor,修改supportParameter的判断方法。
@Override public boolean supportsParameter(MethodParameter parameter) { //springcloud的接口入参没有写@RequestBody,并且是自定义类型对象 也按JSON解析 if (AnnotatedElementUtils.hasAnnotation(parameter.getContainingClass(), FeignClient.class) && isCustomizedType(parameter.getParameterType())) { return true; } return super.supportsParameter(parameter); }
此处的判断逻辑可以根据实际框架进行定义,目的是判断到为Spring Cloud定义的接口,并且是自定义对象时,使用@RequestBody相同的内容转换器。
实现定制化的Processor后,还需要让自定义的配置生效,有两种方案可选:
- 直接替换RequestResponseBodyMethodProcessor,在SpringBoot下需要自定义RequestMappingHandlerAdapter。
- 实现WebMvcConfigurer中的addArgumentResolvers接口
这里采用较为简单的第二种方式,初始化时的消息转换器根据需要进行加载:
public class XXXWebMvcConfig implements WebMvcConfigurer { @Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) { StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(); stringHttpMessageConverter.setWriteAcceptCharset(false); List<HttpMessageConverter<?>> messageConverters = new ArrayList<>(5); messageConverters.add(new ByteArrayHttpMessageConverter()); messageConverters.add(stringHttpMessageConverter); messageConverters.add(new SourceHttpMessageConverter<>()); messageConverters.add(new AllEncompassingFormHttpMessageConverter()); CustomizedMappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new CustomizedMappingJackson2HttpMessageConverter(); jackson2HttpMessageConverter.setObjectMapper(defaultObjectMapper()); messageConverters.add(jackson2HttpMessageConverter); ViomiMvcRequestResponseBodyMethodProcessor resolver = new ViomiMvcRequestResponseBodyMethodProcessor(messageConverters); resolvers.add(resolver); }
修改完成后,微服务的实现类即可去掉@RequestBody注解。
spring cloud 使用feign遇到的问题
spring cloud 使用feign 项目的搭建 在这里就不写了,本文主要讲解在使用过程中遇到的问题以及解决办法
1、示例
@RequestMapping(value = "/generate/password", method = RequestMethod.POST) KeyResponse generatePassword(@RequestBody String passwordSeed);
在这里 只能使用 @RequestMapping(value = "/generate/password", method = RequestMethod.POST) 注解 不能使用
@PostMapping 否则项目启动会报
Caused by: java.lang.IllegalStateException: Method generatePassword not annotated with HTTP method type (ex. GET, POST) 异常
2、首次访问超时问题
原因:Hystrix默认的超时时间是1秒,如果超过这个时间尚未响应,将会进入fallback代码。
而首次请求往往会比较慢(因为Spring的懒加载机制,要实例化一些类),这个响应时间可能就大于1秒了。
解决方法:
<1:配置Hystrix的超时时间改为5秒
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 5000
<2:禁用Hystrix的超时时间
hystrix.command.default.execution.timeout.enabled: false
<3:禁用feign的hystrix 功能
feign.hystrix.enabled: false
注:个人推荐 第一 或者第二种 方法
3、FeignClient接口中,如果使用到@PathVariable,必须指定其value
spring cloud feign 使用 Apache HttpClient
问题:1 没有指定 Content-Type 是情况下 会出现如下异常 ? 这里很纳闷?
Caused by: java.lang.IllegalArgumentException: MIME type may not contain reserved characters
在这里有兴趣的朋友可以去研究下源码
ApacheHttpClient.class private ContentType getContentType(Request request) { ContentType contentType = ContentType.DEFAULT_TEXT; for (Map.Entry<String, Collection<String>> entry : request.headers().entrySet()) // 这里会判断 如果没有指定 Content-Type 属性 就使用上面默认的 text/plain; charset=ISO-8859-1 // 问题出在默认的 contentType : 格式 text/plain; charset=ISO-8859-1 // 转到 ContentType.create(entry.getValue().iterator().next(), request.charset()); 方法中看 if (entry.getKey().equalsIgnoreCase("Content-Type")) { Collection values = entry.getValue(); if (values != null && !values.isEmpty()) { contentType = ContentType.create(entry.getValue().iterator().next(), request.charset()); break; } } return contentType; }
ContentType.class public static ContentType create(final String mimeType, final Charset charset) { final String normalizedMimeType = Args.notBlank(mimeType, "MIME type").toLowerCase(Locale.ROOT); // 问题在这 check 中 valid f方法中 Args.check(valid(normalizedMimeType), "MIME type may not contain reserved characters"); return new ContentType(normalizedMimeType, charset); } private static boolean valid(final String s) { for (int i = 0; i < s.length(); i++) { final char ch = s.charAt(i); // 这里 在上面 text/plain;charset=UTF-8 中出现了 分号 导致检验没有通过 if (ch == '"' || ch == ',' || ch == ';') { return false; } } return true; }
解决办法 :
@RequestMapping(value = "/generate/password", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
注解中指定: Content-Type 即 指定 consumes 的属性值 : 这里 consumes 属性的值在这不做具体讲解,有兴趣的可以去研究下
以上为个人经验,希望能给大家一个参考,也希望大家多多支持猪先飞。
原文出处:https://blog.csdn.net/phoebechen_gz/article/details/82500904
相关文章
基于springcloud异步线程池、高并发请求feign的解决方案
这篇文章主要介绍了基于springcloud异步线程池、高并发请求feign的解决方案,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-25解决Feign切换client到okhttp无法生效的坑(出现原因说明)
这篇文章主要介绍了解决Feign切换client到okhttp无法生效的坑(出现原因说明),具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-25完美解决SpringCloud-OpenFeign使用okhttp替换不生效问题
这篇文章主要介绍了完美解决SpringCloud-OpenFeign使用okhttp替换不生效问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-25如何解决springcloud feign 首次调用100%失败的问题
这篇文章主要介绍了如何解决springcloud feign 首次调用100%失败的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-06-23- 这篇文章主要介绍了Feign接口方法返回值设置方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-07-08
- 这篇文章主要介绍了spring cloud gateway中如何读取请求参数的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-07-15
- 这篇文章主要介绍了使用Feign消费服务时POST/GET请求方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-06-25
解决SpringCloud Feign传对象参数调用失败的问题
这篇文章主要介绍了解决SpringCloud Feign传对象参数调用失败的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-06-24- 这篇文章主要介绍了解决Feign获取异常信息的处理方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-08-27
- JS作为面向对象的弱类型语言,继承也是其非常强大的特性之一,那么这篇文章主要给大家介绍了关于原生Javascript实现继承方式及其优缺点的相关资料,需要的朋友可以参考下...2021-07-21
SpringCloud2020整合Nacos-Bootstrap配置不生效的解决
这篇文章主要介绍了SpringCloud2020整合Nacos-Bootstrap配置不生效的解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-01-25- 这篇文章主要介绍了c# 继承的相关资料,文中讲解的非常细致,代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下...2020-11-03
- 这篇文章主要为大家详细介绍了php构造方法中析构方法在继承中的表现,感兴趣的小伙伴们可以参考一下...2016-04-15
- 这篇文章主要介绍了spring cloud gateway转发服务报错的解决,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-09-02
- 这篇文章主要介绍了解决springcloud-gateway限流遇到的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-07-16
- 这篇文章主要介绍了javascript中的3种继承实现方法,包括使用Object.create实现类式继承、使用utilities工具包自带的util.inherites、使用extends关键字,非常的实用,希望对大家了解javascript继承能够有所帮助...2016-01-30
- 这篇文章主要为大家举例介绍了js对象继承的几种模式,内容很全面,感兴趣的小伙伴们可以参考一下...2016-01-26
- 这篇文章主要给大家介绍了关于js继承的6种方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-04-06
SpringCloud @FeignClient参数的用法解析
这篇文章主要介绍了SpringCloud @FeignClient参数的用法,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-10-21- 这篇文章主要介绍了使用SpringCloudAlibaba整合Dubbo,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-10-11