简介
Feign 是一个 Java 到 HTTP 客户端的粘合剂。Feign 的目标是以最少的开销和代码把 你的代码连接到 http api 上。通过定制的编解码器和错误处理,你可以请求任何基于文本的 http api 。
原理
通过处理注解信息来生成模板化请求。在发出请求前,参数直接应用到这些模板上。这限制了 Feign 只支持基于文本的 api,这显著简化了系统的一些方面如重放请求。
为什么选择 Feign
-
依赖问题。目前项目组用的是 Hessian 做远程调用,由于 Hessian 存在对 jar 包的依赖,特别是一些项目升级到 JDK 1.8,采用 Maven 构建;而老的一些任然采用 1.6 ,是个简单的 Eclipse 工程,导致打包、部署非常麻烦。
-
依赖于接口,使用简洁。对于客户端,只依赖于接口类,通过 Spring 注入实现,迁移基本不需要很大的改动。
-
与 Spring Cloud 集成。Feign 本身是 Spring Cloud 的一个组件,可以通过 Ribbon 做路由,可以进一步提升服务化。
-
系统对性能的要求并不是那种很严苛的,基于文本的调用也方便调试。
使用举例
首先要定义 Java 代码到 HTTP 请求模板的注解,如下,在接口的方法上进行。
public interface HttpApi {
// 提交一些简单类型的参数,返回一个复合对象的列表
@RequestLine("GET /repos/{owner}/{repo}/contributors")
List<Contributor> contributors(@Param("owner") String owner, @Param("repo") String repo);
// 指定 http 头的一些字段。提交复合类型的参数
@RequestLine("PUT /repos/contributors/{id}")
@Headers("Content-Type: application/json")
void putContributor(@Param("id") String id, Contributor contributor);
// 定制请求体的内容
@RequestLine("POST /login")
@Headers("Content-Type: application/json")
// json 的花括号必须进行转义
@Body("%7B\"name\": \"{name}\", \"password\": \"{password}\"%7D")
void login(@Param("name") String name, @Param("password") String password);
}
调用;
HttpApi httpApi = Feign.builder().decoder(new GsonDecoder()).encoder(new GsonEncoder()).target(HttpApi.class,
"https://api.github.com");
List<Contributor> contributors = httpApi.contributors("OpenFeign", "feign");
如果参数或返回值有复合对象,Feign 内置的编解码器是不支持的,可以使用基于 Gson 实现的 feign-gson 库。
构建器的 target 方法接收一个接口类和目标 http api 的基路径(跟 @RequestLine
里指定的路径组合起来就是完整的请求路径)。
使用方请求 http api 时就像调用本地方法一样:httpApi.contributors("OpenFeign", "feign");
。
对于没有在 注解里指定的参数,即使用了 @Param
注解,都放进一个 Map 里,编码后作为请求体。
这会导致服务器端没法把参数映射到多个 POJO 上。
@RequestLine("PUT /repos/contributors/params/{id}")
@Headers("Content-Type: application/json")
void putContributorParam(@Param("id") String id, @Param("contributor1") String contributor1,
@Param("contributor2") String contributor2);
以上面的方式提交的 Feign 会把 contributor1, contributor2
参数放进一个 Map 里,然后把这个 Map 序列化为 JSON 串作为请求体发送出去。这也是默认的方式。
如果需要以 方式发送请求,需要手工对参数值进行 URLEncode 。
@RequestLine("PUT /repos/contributors/params/{id}")
@Headers("Content-Type: application/x-www-form-urlencoded")
@Body("contributor1={contributor1}&contributor2={contributor2}")
void putContributorParam(@Param("id") String id, @Param("contributor1") String contributor1,
@Param("contributor2") String contributor2);
调用: httpApi.putContributorParam("123654", "+-*/=中文&contributor2=123", "0123457896");
Content-Type: application/x-www-form-urlencoded
Content-Length: 42
contributor1=+-*/=&contributor2=0123457896
服务端得到的参数的 contributor1 是 " -*/=中文"
,contributor2 是 "123,0123457896"
。
欢迎关注我的微信公众号: coderbee笔记,可以更及时回复你的讨论。