Feign学习笔记
通过 Controller 实现 Feign 接口简化代码
使用过 Feign 的同学应该会发现,注解为 Feign 调用服务内的接口方法和被调用方的接口方法是完全等价的编码方式,每当我们需要调用其他微服务的方法,都需要把对方的接口照着重写一遍,非常麻烦,这时可以通过 Controller 实现 Feign 接口简化代码
将 Controller 层的接口以及VO、请求参数封装类等提取出来放到一个新的 maven 模块 xxx-service-api 中,将 @FeignClient
注解打到 Controller 层的接口上,如果别的微服务需要调用本服务的接口,则只需将该模块打成jar包并发布到共用的依赖库中(或者直接给它),在需要的微服务中引入就可以使用了,非常方便
建议将 Controller 层除必须打到实现类上的注解外其他的注解(比如Swagger注解)都打到接口上,这样能够提供更加优质的接口说明,比如 Swagger 注解可以随着接口jar包暴露给调用方起到注释的作用,请求路径(RequestMapping)、请求参数映射(@RequestParam、@RequestBody)等规则也都一目了然
Feign客户端(调用方)捕获服务端(被调用方)异常
问题描述
当Feign客户端调用服务端时,如果服务端出现了异常,那么异常会被服务端的统一异常处理进行封装并返回
这时如果服务端的统一异常处理没有设置响应状态为非2XX(默认是200),那么在客户端就不会发生异常,对客户端来说这次Feign调用是成功的,但是接收到的响应体内容并不是业务需要的数据而是服务端封装的异常应答,这意味着需要在业务代码中自行对Feign调用发生的异常进行判断和处理,失去了自动异常处理的意义
解决办法
所以在服务端发生异常时,客户端得到的响应状态应该为非2XX,这时才会自动走异常处理流程
但是,Feign调用发生错误时(响应状态码非2XX)会通过接口 ErrorDecoder
的默认实现 Default
类进行处理,客户端真正捕获到的异常是经过 Default
类处理之后抛出的 FeignException
异常,所以客户端如果想根据原始的服务端异常响应信息进行异常处理,必须实现 ErrorDecoder
接口并重写 decode
方法,在 decode
方法中进行异常的处理封装返回
需要注意的是,Feign调用错误分为两种,一种是服务器端错误(响应状态为5XX),另一种是客户端错误(响应状态为4XX)或网络错误
针对服务器端错误,响应体就是已经由服务器端统一异常处理封装好的异常信息,这时如果客户端和服务端使用的是同一个异常响应结构对象,那么可以直接使用已经封装好的响应体;但是对于客户端错误,响应体是由Feign自动生成的,这时必须进行处理封装为自定义的异常响应结构对象
常见问题
使用 Feign 远程调用时报错:Service id not legal hostname(xx_sss)
原因是 Feign 不支持下划线 "_",支持 "-",改成 "xx-sss" 即可