一、背景描述
公司做的智能家居系统改为微服务框架,各个微服务之前相互调用。
今天在做测试的时候后台系统报了一个Caused by: java.lang.IllegalArgumentException: method GET must not have a request body错误,然后检查了请求链路从前到后一路上全部是GET请求方式。通过Debug调试,页面请求可以打进serviceA,参数也可以携带进方法内,一步一步向下走,发现通过FeignClient调用serviceB的时候,报出这个异常。
二、出错的代码
以下两个接口都是ServiceA通过FiegnClient调用ServiceB的接口(通过FeignClient调用的接口)
第一种ServiceB接口的代码
/** * 根据主机sn查询远程运维记录 * @param distanceMaintainRecordQuery * @return */ @GetMapping("/client/v1.0/distanceMaintain/pageMaintain") PageResult<DistanceMaintainRecordBO> pageMaintain(DistanceMaintainRecordQuery distanceMaintainRecordQuery);
第二种ServiceB接口的代码
/** * 查询屏保详情 * * @param id * @return */ @GetMapping("/client/v1.0/screenSaver/info") CommResponse<ScreenSaverBO> info(Integer id);
三、出错原因
报出这个异常的原因是:这个接口的请求方式是GET请求,接受的参数是一个对象(包含多个参数),而通过FeignClient调用的话GET请求方式是无法解析对象的,所以使用上述代码会报Caused by: java.lang.IllegalArgumentException: method GET must not have a request body错。
其实FeignClient是支持对象传递的,但是得是Map形式,而且不能为空,与spring在机制上不兼容,因此无法使用。
而spring cloud在2.1.x版本中提供了@SpringQueryMap注解,可以传递对象参数,框架自动解析,只可惜啊,得是2.1.0以后的版本。
对于上述第二种接口GET请求只传一个参数,通过FeignClient调用,同样也不支持。报错信息和第一种情况一模一样。
四、解决方案
4.1 方案1:POST请求 + 注解
将ServiceB接口的请求方式改为POST,同时接受的参数前面加上@RequestBody注解,改正后的代码如下:
/** * 根据主机sn查询远程运维记录 * @param distanceMaintainRecordQuery * @return */ @PostMapping("/client/v1.0/distanceMaintain/pageMaintain") PageResult<DistanceMaintainRecordBO> pageMaintain(@RequestBody DistanceMaintainRecordQuery distanceMaintainRecordQuery);
4.2 方案2:GET请求 + @SpringQueryMap注解
/** * 根据主机sn查询远程运维记录 * @param distanceMaintainRecordQuery * @return */ @GetMapping("/client/v1.0/distanceMaintain/pageMaintain") PageResult<DistanceMaintainRecordBO> pageMaintain(@SpringQueryMap DistanceMaintainRecordQuery distanceMaintainRecordQuery);
使用方案2的时候一定要注意Spring Cloud的版本,2.1.x以下的不支持哦,只有2.1.x以上版本才能解析参数。
4.3 方案3:GET请求 + @RequestParam("xxx")注解
/** * 查询屏保详情 * * @param id * @return */ @GetMapping("/client/v1.0/screenSaver/info") CommResponse<ScreenSaverBO> info(@RequestParam("id") Integer id);
需要注意的是:
1、spring cloud项目使用FeignClient的时候GET请求方式无法解析对象参数
2、spring cloud项目使用FeignClient的时候GET请求有时候也无法解析单个参数值
拓展:如何使用Feign构造多参数的请求:如何使用Feign构造多参数的请求 | 周立的博客 - 关注Spring Cloud、Docker