Feign 可以在服务消费者和服务提供者之间进行GET和Post多参数传递的。springmvc中是支持GET方法绑定pojo的,但是Feign 并未覆盖springmvc中的所有方法,目前解决方式很多,常见的有如下方式:
- 把pojo拆分成一个个单独的属性做为方法参数
- 方法参数作为map传递
如果不这么解决当使用对象做为参数时会报以下错误:
当然以下错误的原因还有可能是通过Feign 进行服务间调用时,GET方法的参数没有加@PathVariable或@RequestParam注解
feign.FeignException$MethodNotAllowed: status 405 reading UserProviderClientService#save(UserEntity) at feign.FeignException.clientErrorStatus(FeignException.java:167) at feign.FeignException.errorStatus(FeignException.java:141) at feign.FeignException.errorStatus(FeignException.java:133) at feign.codec.ErrorDecoder$Default.decode(ErrorDecoder.java:92) at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:151) at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:80) at feign.hystrix.HystrixInvocationHandler$1.run(HystrixInvocationHandler.java:109) at com.netflix.hystrix.HystrixCommand$2.call(HystrixCommand.java:302) at com.netflix.hystrix.HystrixCommand$2.call(HystrixCommand.java:298) at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:46) at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:35) at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) at rx.Observable.unsafeSubscribe(Observable.java:10327) at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:51) at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:35) at rx.Observable.unsafeSubscribe(Observable.java:10327) at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:41) at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:30) at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) at rx.Observable.unsafeSubscribe(Observable.java:10327) at rx.internal.operators.OperatorSubscribeOn$SubscribeOnSubscriber.call(OperatorSubscribeOn.java:100) at com.netflix.hystrix.strategy.concurrency.HystrixContexSchedulerAction$1.call(HystrixContexSchedulerAction.java:56) at com.netflix.hystrix.strategy.concurrency.HystrixContexSchedulerAction$1.call(HystrixContexSchedulerAction.java:47) at org.springframework.cloud.sleuth.instrument.async.TraceCallable.call(TraceCallable.java:70) at com.netflix.hystrix.strategy.concurrency.HystrixContexSchedulerAction.call(HystrixContexSchedulerAction.java:69) at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748)
上面的问题还可以通过拦截器去解决,Feign 提供了一个请求拦截器RequestInterceptor,可以在请求之前给请求加请求头等功能,有点类似于spring cloud gateway中的断言工厂,有关spring cloud gateway可以查看springcloud 入门 之网关 springcloud gateway
代码如下:
@Component public class FeignRequestInterceptor implements RequestInterceptor { @Autowired private ObjectMapper objectMapper; /** * Called for every request. Add data using methods on the supplied {@link RequestTemplate}. * * @param template */ @Override public void apply(RequestTemplate template) { final String method = template.method(); final Request.Body requestBody = template.requestBody(); if ("GET".equals(method) && requestBody != null && requestBody.bodyTemplate() != null) { final String requestParam = requestBody.asString(); try { //把之前的请求体清空 template.body(Request.Body.empty()); final JsonNode jsonNode = objectMapper.readTree(requestParam); Map<String, Collection<String>> params = new HashMap<>(jsonNode.size()); buildQuery(jsonNode , "" , params); template.queries(params); } catch (IOException e) { //可根据项目需求处理异常 e.printStackTrace(); } } } private void buildQuery(JsonNode jsonNode, String path, Map<String, Collection<String>> queries) { if (!jsonNode.isContainerNode()) { // 叶子节点 if (jsonNode.isNull()) { return; } Collection<String> values = queries.computeIfAbsent(path, k -> new ArrayList<>()); values.add(jsonNode.asText()); return; } if (jsonNode.isArray()) { // 数组节点 Iterator<JsonNode> it = jsonNode.elements(); while (it.hasNext()) { buildQuery(it.next(), path, queries); } } else { Iterator<Map.Entry<String, JsonNode>> it = jsonNode.fields(); while (it.hasNext()) { Map.Entry<String, JsonNode> entry = it.next(); if (StringUtils.hasText(path)) { buildQuery(entry.getValue(), path + "." + entry.getKey(), queries); } else { // 根节点 buildQuery(entry.getValue(), entry.getKey(), queries); } } } } }
通过FeignRequestInterceptor拦截器就能解决GET方法无法传递pojo的问题了。
有关feign的学习可以参考springcloud 入门(3) 声明式调用 Feign
学习更多关于springcloud的可以关注我的 springcloud 专栏
GitHub地址:
https://github.com/ArronSun/micro-services-practice.git
参考:
《重新定义springcloud 实战》
能力一般,水平有限,如有错误,请多指出。
如果对你有用点个关注给个赞呗