spring cloud——feign为GET请求时的对象参数传递
Posted Devil丶俊锅
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring cloud——feign为GET请求时的对象参数传递相关的知识,希望对你有一定的参考价值。
一、问题重现
楼主在使用feign进行声明式服务调用的时候发现,当GET请求为多参数时,为方便改用DTO对象进行参数传递。但是,在接口调用时feign会抛出一个405的请求方式错误:
{"timestamp":1540713334390,"status":405,"error":"Method Not Allowed", "exception":"org.springframework.web.HttpRequestMethodNotSupportedException","message":"Request method \'POST\' not supported","path":"/role/get"}
API接口层代码如下:
@RequestMapping(value = "/role") public interface RoleService { @GetMapping(value = "/get") Result<RuleInfoVO> getRoleInfo(RoleInfoRequest request); }
服务端实现:
@Slf4j @RestController public class RoleInfoResource implements RoleService { @Override public Result<RuleInfoVO> getRoleInfo(RoleInfoRequest request) { log.info("params of getRoleInfo:{}",request); return new Result<>(); } }
feign客户端调用:
@Slf4j @RestController @RequestMapping(value = "/role") public class RoleController { @Autowired private RoleInfoApi roleInfoApi; @GetMapping(value = "/get") public Result<RuleInfoVO> getRuleInfo(RoleInfoRequest request){ log.info("params of getRuleInfo:{}",request); Result<RuleInfoVO> result = this.roleInfoApi.getRoleInfo(request); log.info("result of getRuleInfo:{}",result); return result; } }
检查feign调用方式与服务端所声明的方式一致,但是为什么为抛出405异常?带着该疑问稍微跟了一下源码,发现feign默认的远程调用使用的是jdk底层的HttpURLConnection,这在feign-core包下的Client接口中的convertAndSend方法可看到:
if (request.body() != null) { if (contentLength != null) { connection.setFixedLengthStreamingMode(contentLength); } else { connection.setChunkedStreamingMode(8196); } connection.setDoOutput(true); OutputStream out = connection.getOutputStream(); if (gzipEncodedRequest) { out = new GZIPOutputStream(out); } else if (deflateEncodedRequest) { out = new DeflaterOutputStream(out); } try { out.write(request.body()); } finally { try { out.close(); } catch (IOException suppressed) { // NOPMD } } }
该段代码片段会判断requestBody是否为空,我们知道GET请求默认是不会有requestBody的,因此该段代码会执行到HttpURLConnection中的 private synchronized OutputStream getOutputStream0() throws IOException; 方法:
1 if (this.method.equals("GET")) { 2 this.method = "POST"; 3 }
最关键的代码片段已显示当请求方式为GET请求,会将该GET请求修改为POST请求,这也就是4返回05状态的根本原因。
二、解决方案
幸运的是,feign为我们提供了相应的配置解决方案。我们只需将feign底层的远程调用由HttpURLConnection修改为其他远程调用方式即可。而且基本不需要修改太多的代码,只需再依赖中加入feign-httpclient包的依赖,并在@RequestMapping注解中加入consumes的属性即可:
1 compile \'io.github.openfeign:feign-httpclient:9.5.1\'
楼主用的gradle,使用maven的大佬请自行更改为maven的配置方式。
增加@GetMapping注解的consumes属性,使用@RequestMapping的大佬也一样:
1 @RequestMapping(value = "/role") 2 public interface RoleService { 3 4 5 @GetMapping(value = "/get",consumes = MediaType.APPLICATION_JSON_UTF8_VALUE) 6 Result<RuleInfoVO> getRoleInfo(@RequestBody RoleInfoRequest request); 7 8 }
大功告成:
源代码请各位大佬移步:https://github.com/LJunChina/cloud-solution-staging
以上是关于spring cloud——feign为GET请求时的对象参数传递的主要内容,如果未能解决你的问题,请参考以下文章
带有 List 参数的 Spring Cloud Feign Client @RequestParam 创建错误的请求
如何使用 Spring Cloud 将 Hystrix 属性设置为 Feign 请求?
Spring Cloud Feign 报:Method not annotated with HTTP method type (ex. GET, POST)