如何解决Spring Cloud中使用Feign,@RequestBody无法继承问题

发布时间:2021-10-22 10:09:48 作者:iii
来源:亿速云 阅读:534

本篇内容主要讲解“如何解决Spring Cloud中使用Feign,@RequestBody无法继承问题”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何解决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后,还需要让自定义的配置生效,有两种方案可选:

这里采用较为简单的第二种方式,初始化时的消息转换器根据需要进行加载:

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 属性的值在这不做具体讲解,有兴趣的可以去研究下

到此,相信大家对“如何解决Spring Cloud中使用Feign,@RequestBody无法继承问题”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

推荐阅读:
  1. Bug集锦-Spring Cloud Feign调用其它接口报错
  2. spring cloud feign会遇到什么坑

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

springcloud feign @requestbody

上一篇:如何移植linux kernel及含busybox的yaffs2文件系统镜像

下一篇:Linux 驱动开发中测试按键的示例分析

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》