Feign api调用方式

Feign使用简介

基本用法

基本的使用如下所示,一个对于canonical Retrofit sample的适配。

interface GitHub {// RequestLine注解声明请求方法和请求地址,可以允许有查询参数@RequestLine("GET /repos/{owner}/{repo}/contributors")List<Contributor> contributors(@Param("owner") String owner, @Param("repo") String repo);
}static class Contributor {String login;int contributions;
}public static void main(String... args) {GitHub github = Feign.builder().decoder(new GsonDecoder()).target(GitHub.class, "https://api.github.com");// Fetch and print a list of the contributors to this library.List<Contributor> contributors = github.contributors("OpenFeign", "feign");for (Contributor contributor : contributors) {System.out.println(contributor.login + " (" + contributor.contributions + ")");}
}

 


自定义

Feign 有许多可以自定义的方面。举个简单的例子,你可以使用 Feign.builder() 来构造一个拥有你自己组件的API接口。如下:

interface Bank {@RequestLine("POST /account/{id}")Account getAccountInfo(@Param("id") String id);
}
...
// AccountDecoder() 是自己实现的一个Decoder
Bank bank = Feign.builder().decoder(new AccountDecoder()).target(Bank.class, "https://api.examplebank.com");

 


多种接口

Feign可以提供多种API接口,这些接口都被定义为 Target<T> (默认的实现是 HardCodedTarget<T>), 它允许在执行请求前动态发现和装饰该请求。 
举个例子,下面的这个模式允许使用当前url和身份验证token来装饰每个发往身份验证中心服务的请求。

CloudDNS cloudDNS = Feign.builder().target(new CloudIdentityTarget<CloudDNS>(user, apiKey));

 


示例

Feign 包含了 GitHub 和 Wikipedia 客户端的实现样例.相似的项目也同样在实践中运用了Feign。尤其是它的示例后台程序。


Feign集成模块

Feign 可以和其他的开源工具集成工作。你可以将这些开源工具集成到 Feign 中来。目前已经有的一些模块如下:

Gson

Gson 包含了一个编码器和一个解码器,这个可以被用于JSON格式的API。 
添加 GsonEncoder 以及 GsonDecoder 到你的 Feign.Builder 中, 如下:

GsonCodec codec = new GsonCodec();
GitHub github = Feign.builder().encoder(new GsonEncoder()).decoder(new GsonDecoder()).target(GitHub.class, "https://api.github.com");

 

Maven依赖:

<!-- https://mvnrepository.com/artifact/com.netflix.feign/feign-gson -->
<dependency><groupId>com.netflix.feign</groupId><artifactId>feign-gson</artifactId><version>8.18.0</version>
</dependency>

 

Jackson

Jackson 包含了一个编码器和一个解码器,这个可以被用于JSON格式的API。 
添加 JacksonEncoder 以及 JacksonDecoder 到你的 Feign.Builder 中, 如下:

GitHub github = Feign.builder().encoder(new JacksonEncoder()).decoder(new JacksonDecoder()).target(GitHub.class, "https://api.github.com");

 

Maven依赖:

  <!-- https://mvnrepository.com/artifact/com.netflix.feign/feign-gson --><dependency><groupId>com.netflix.feign</groupId><artifactId>feign-jackson</artifactId><version>8.18.0</version></dependency>

 

Sax

SaxDecoder 用于解析XML,并兼容普通JVM和Android。下面是一个配置sax来解析响应的例子:

api = Feign.builder().decoder(SAXDecoder.builder().registerContentHandler(UserIdHandler.class).build()).target(Api.class, "https://apihost");

 

Maven依赖:

<dependency><groupId>com.netflix.feign</groupId><artifactId>feign-sax</artifactId><version>8.18.0</version>
</dependency>

 

JAXB

JAXB 包含了一个编码器和一个解码器,这个可以被用于XML格式的API。 
添加 JAXBEncoder 以及 JAXBDecoder 到你的 Feign.Builder 中, 如下:

api = Feign.builder().encoder(new JAXBEncoder()).decoder(new JAXBDecoder()).target(Api.class, "https://apihost");

 

Maven依赖:

<!-- https://mvnrepository.com/artifact/com.netflix.feign/feign-gson -->
<dependency><groupId>com.netflix.feign</groupId><artifactId>feign-jaxb</artifactId><version>8.18.0</version>
</dependency>

JAX-RS

JAXRSContract 使用 JAX-RS 规范重写覆盖了默认的注解处理。下面是一个使用 JAX-RS 的例子:

interface GitHub {@GET @Path("/repos/{owner}/{repo}/contributors")List<Contributor> contributors(@PathParam("owner") String owner, @PathParam("repo") String repo);
}
// contract 方法配置注解处理器,注解处理器定义了哪些注解和值是可以作用于接口的
GitHub github = Feign.builder().contract(new JAXRSContract()).target(GitHub.class, "https://api.github.com");

 

Maven依赖:

<!-- https://mvnrepository.com/artifact/com.netflix.feign/feign-gson -->
<dependency><groupId>com.netflix.feign</groupId><artifactId>feign-jaxrs</artifactId><version>8.18.0</version>
</dependency>

 

OkHttp

OkHttpClient 使用 OkHttp 来发送 Feign 的请求,OkHttp 支持 SPDY (SPDY是Google开发的基于TCP的传输层协议,用以最小化网络延迟,提升网络速度,优化用户的网络使用体验),并有更好的控制http请求。 
要让 Feign 使用 OkHttp ,你需要将 OkHttp 加入到你的环境变量中区,然后配置 Feign 使用 OkHttpClient,如下:

GitHub github = Feign.builder().client(new OkHttpClient()).target(GitHub.class, "https://api.github.com");

 

Maven依赖:

<!-- https://mvnrepository.com/artifact/com.netflix.feign/feign-gson -->
<dependency><groupId>com.netflix.feign</groupId><artifactId>feign-okhttp</artifactId><version>8.18.0</version>
</dependency>

 

Ribbon

RibbonClient 重写了 Feign 客户端的对URL的处理,其添加了 智能路由以及一些其他由Ribbon提供的弹性功能。 
集成Ribbon需要你将ribbon的客户端名称当做url的host部分来传递,如下:

// myAppProd是你的ribbon client name
MyService api = Feign.builder().client(RibbonClient.create()).target(MyService.class, "https://myAppProd");

 

Maven依赖:

<!-- https://mvnrepository.com/artifact/com.netflix.feign/feign-gson -->
<dependency><groupId>com.netflix.feign</groupId><artifactId>feign-ribbon</artifactId><version>8.18.0</version>
</dependency>

 

Hystrix

HystrixFeign 配置了 Hystrix 提供的熔断机制。 
要在 Feign 中使用 Hystrix ,你需要添加Hystrix模块到你的环境变量,然后使用 HystrixFeign 来构造你的API:

MyService api = HystrixFeign.builder().target(MyService.class, "https://myAppProd");

 

Maven依赖:

<!-- https://mvnrepository.com/artifact/com.netflix.feign/feign-gson -->
<dependency><groupId>com.netflix.feign</groupId><artifactId>feign-hystrix</artifactId><version>8.18.0</version>
</dependency>

 

SLF4J

SLF4JModule 允许你使用 SLF4J 作为 Feign 的日志记录模块,这样你就可以轻松的使用 LogbackLog4J , 等 来记录你的日志. 
要在 Feign 中使用 SLF4J ,你需要添加SLF4J模块和对应的日志记录实现模块(比如Log4J)到你的环境变量,然后配置 Feign使用Slf4jLogger :

GitHub github = Feign.builder().logger(new Slf4jLogger()).target(GitHub.class, "https://api.github.com");

 

Maven依赖:

<!-- https://mvnrepository.com/artifact/com.netflix.feign/feign-gson -->
<dependency><groupId>com.netflix.feign</groupId><artifactId>feign-slf4j</artifactId><version>8.18.0</version>
</dependency>

 


Feign 组成

Decoders

Feign.builder() 允许你自定义一些额外的配置,比如说如何解码一个响应。假如有接口方法返回的消息不是 ResponseStringbyte[] 或者 void 类型的,那么你需要配置一个非默认的解码器。 
下面是一个配置使用JSON解码器(使用的是feign-gson扩展)的例子:

GitHub github = Feign.builder().decoder(new GsonDecoder()).target(GitHub.class, "https://api.github.com");

 

假如你想在将响应传递给解码器处理前做一些额外的处理,那么你可以使用mapAndDecode方法。一个用例就是使用jsonp服务的时候:

// 貌似1.8.0版本中沒有mapAndDecode这个方法。。。
JsonpApi jsonpApi = Feign.builder().mapAndDecode((response, type) -> jsopUnwrap(response, type), new GsonDecoder()).target(JsonpApi.class, "https://some-jsonp-api.com");

 

Encoders

发送一个Post请求最简单的方法就是传递一个 String 或者 byte[] 类型的参数了。你也许还需添加一个Content-Type请求头,如下:

interface LoginClient {@RequestLine("POST /")@Headers("Content-Type: application/json")void login(String content);
}
...
client.login("{\"user_name\": \"denominator\", \"password\": \"secret\"}");

 

通过配置一个解码器,你可以发送一个安全类型的请求体,如下是一个使用 feign-gson 扩展的例子:

static class Credentials {final String user_name;final String password;Credentials(String user_name, String password) {this.user_name = user_name;this.password = password;}
}interface LoginClient {@RequestLine("POST /")void login(Credentials creds);
}
...
LoginClient client = Feign.builder().encoder(new GsonEncoder()).target(LoginClient.class, "https://foo.com");client.login(new Credentials("denominator", "secret"));

 

@Body templates

@Body注解申明一个请求体模板,模板中可以带有参数,与方法中 @Param 注解申明的参数相匹配,使用方法如下

interface LoginClient {@RequestLine("POST /")@Headers("Content-Type: application/xml")@Body("<login \"user_name\"=\"{user_name}\" \"password\"=\"{password}\"/>")void xml(@Param("user_name") String user, @Param("password") String password);@RequestLine("POST /")@Headers("Content-Type: application/json")// json curly braces must be escaped!// 这里JSON格式需要的花括号居然需要转码,有点蛋疼了。@Body("%7B\"user_name\": \"{user_name}\", \"password\": \"{password}\"%7D")void json(@Param("user_name") String user, @Param("password") String password);
}
...
// <login "user_name"="denominator" "password"="secret"/>
client.xml("denominator", "secret"); 
// {"user_name": "denominator", "password": "secret"}
client.json("denominator", "secret"); 

 

Headers

Feign 支持给请求的api设置或者请求的客户端设置请求头

给API设置请求头

  • 使用 @Headers 设置静态请求头
// 给BaseApi中的所有方法设置Accept请求头
@Headers("Accept: application/json")
interface BaseApi<V> {// 单独给put方法设置Content-Type请求头@Headers("Content-Type: application/json") @RequestLine("PUT /api/{key}") void put(@Param("key") String, V value); }
  • 设置动态值的请求头
@RequestLine("POST /")
@Headers("X-Ping: {token}")
void post(@Param("token") String token);
  • 设置key和value都是动态的请求头 
    有些API需要根据调用时动态确定使用不同的请求头(e.g. custom metadata header fields such as “x-amz-meta-” or “x-goog-meta-“), 
    这时候可以使用 @HeaderMap 注解,如下:
// @HeaderMap 注解设置的请求头优先于其他方式设置的
@RequestLine("POST /")
void post(@HeaderMap Map<String, Object> headerMap);

给Target设置请求头

有时我们需要在一个API实现中根据不同的endpoint来传入不同的Header,这个时候我们可以使用自定义的RequestInterceptor 或 Target来实现. 
通过自定义的 RequestInterceptor 来实现请查看 Request Interceptors 章节. 
下面是一个通过自定义Target来实现给每个Target设置安全校验信息Header的例子:

  static class DynamicAuthTokenTarget<T> implements Target<T> {public DynamicAuthTokenTarget(Class<T> clazz,UrlAndTokenProvider provider,ThreadLocal<String> requestIdProvider);...@Overridepublic Request apply(RequestTemplate input) { TokenIdAndPublicURL urlAndToken = provider.get(); if (input.url().indexOf("http") != 0) { input.insert(0, urlAndToken.publicURL); } input.header("X-Auth-Token", urlAndToken.tokenId); input.header("X-Request-ID", requestIdProvider.get()); return input.request(); } } ... Bank bank = Feign.builder() .target(new DynamicAuthTokenTarget(Bank.class, provider, requestIdProvider));

这种方法的实现依赖于给Feign 客户端设置的自定义的RequestInterceptor 或 Target。可以被用来给一个客户端的所有api请求设置请求头。比如说可是被用来在header中设置身份校验信息。这些方法是在线程执行api请求的时候才会执行,所以是允许在运行时根据上下文来动态设置header的。 
比如说可以根据线程本地存储(thread-local storage)来为不同的线程设置不同的请求头。


高级用法

Base APIS

有些请求中的一些方法是通用的,但是可能会有不同的参数类型或者返回类型,这个时候可以这么用:

// 通用API
interface BaseAPI {@RequestLine("GET /health")String health();@RequestLine("GET /all") List<Entity> all(); } // 继承通用API interface CustomAPI extends BaseAPI { @RequestLine("GET /custom") String custom(); } // 各种类型有相同的表现形式,定义一个统一的API @Headers("Accept: application/json") interface BaseApi<V> { @RequestLine("GET /api/{key}") V get(@Param("key") String key); @RequestLine("GET /api") List<V> list(); @Headers("Content-Type: application/json") @RequestLine("PUT /api/{key}") void put(@Param("key") String key, V value); } // 根据不同的类型来继承 interface FooApi extends BaseApi<Foo> { } interface BarApi extends BaseApi<Bar> { }

Logging

你可以通过设置一个 Logger 来记录http消息,如下:

GitHub github = Feign.builder().decoder(new GsonDecoder()).logger(new Logger.JavaLogger().appendToFile("logs/http.log")).logLevel(Logger.Level.FULL).target(GitHub.class, "https://api.github.com");

也可以参考上面的 SLF4J 章节的说明

Request Interceptors

当你希望修改所有的的请求的时候,你可以使用Request Interceptors。比如说,你作为一个中介,你可能需要为每个请求设置 X-Forwarded-For

static class ForwardedForInterceptor implements RequestInterceptor {@Override public void apply(RequestTemplate template) { template.header("X-Forwarded-For", "origin.host.com"); } } ... Bank bank = Feign.builder() .decoder(accountDecoder) .requestInterceptor(new ForwardedForInterceptor()) .target(Bank.class, "https://api.examplebank.com");

或者,你可能需要实现Basic Auth,这里有一个内置的基础校验拦截器 BasicAuthRequestInterceptor

Bank bank = Feign.builder().decoder(accountDecoder).requestInterceptor(new BasicAuthRequestInterceptor(username, password)).target(Bank.class, "https://api.examplebank.com");

Custom @Param Expansion

在使用 @Param 注解给模板中的参数设值的时候,默认的是使用的对象的 toString() 方法的值,通过声明 自定义的Param.Expander,用户可以控制其行为,比如说格式化 Date 类型的值:

// 通过设置 @Param 的 expander 为 DateToMillis.class 可以定义Date类型的值
@RequestLine("GET /?since={date}") 
Result list(@Param(value = "date", expander = DateToMillis.class) Date date);

Dynamic Query Parameters

动态查询参数支持,通过使用 @QueryMap 可以允许动态传入请求参数,如下:

@RequestLine("GET /find")
V find(@QueryMap Map<String, Object> queryMap);

Static and Default Methods

如果你使用的是JDK 1.8+ 的话,那么你可以给接口设置统一的默认方法和静态方法,这个事JDK8的新特性,如下:

interface GitHub {@RequestLine("GET /repos/{owner}/{repo}/contributors")List<Contributor> contributors(@Param("owner") String owner, @Param("repo") String repo); @RequestLine("GET /users/{username}/repos?sort={sort}") List<Repo> repos(@Param("username") String owner, @Param("sort") String sort); default List<Repo> repos(String owner) { return repos(owner, "full_name"); } /** * Lists all contributors for all repos owned by a user. */ default List<Contributor> contributors(String user) { MergingContributorList contributors = new MergingContributorList(); for(Repo repo : this.repos(owner)) { contributors.addAll(this.contributors(user, repo.getName())); } return contributors.mergeResult(); } static GitHub connect() { return Feign.builder() .decoder(new GsonDecoder()) .target(GitHub.class, "https://api.github.com"); } }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/450384.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

预处理

C语言##预算符 和#运算符一样&#xff0c;##运算符可以用于宏函数的替换部分。这个运算符把两个语言符号组合成单个语言符号。看例子&#xff1a;#define XNAME(n) x ## n如果这样使用宏&#xff1a;XNAME(8)则会被展开成这样&#xff1a;x8看明白了没&#xff1f; ##就是个粘合…

Lambda表达式使用2

1.概述    本篇主要介绍lambda中常用的收集器&#xff0c;收集器的作用就是从数据流中生成需要的数据接口。    最常用的就是Collectors.toList()&#xff0c;只要将它传递给collect()函数&#xff0c;就能够使用它了。    在我们使用收集器的时候经常会用到“方法…

notepad++ 使用去掉自动检查红线

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 notepad新升级了之后就有自动判断的红线&#xff0c;单词拼错了就给提示&#xff0c;看着这红线实在难受 在 菜单选项&#xff1a;[插件…

cAdvisor+InfluxDB+Grafana 监控Docker

容器的监控方案其实有很多&#xff0c;有docker自身的docker stats命令、有Scout、有Data Dog等等&#xff0c;本文主要和大家分享一下比较经典的容器开源监控方案组合&#xff1a;cAdvisorInfluxDBGrafan 一、概念 1). InfluxDB是什么nfluxDB是用GO语言编写的一个开源分布式时…

C语言return关键字

return 用来终止一个函数并返回其后面跟着的值。return &#xff08;Val&#xff09;&#xff1b;//此括号可以省略。但一般不省略&#xff0c;尤其在返回一个表达式的值时。return 可以返回些什么东西呢&#xff1f;看下面例子&#xff1a;char * Func(void){char str[30];…r…

win7旗舰版怎么降级到专业版

一、操作准备及注意事项 1、UltraISO光盘制作工具9.5 2、备份C盘及桌面文件 二、win7旗舰版改成专业版的步骤 1、当前系统为Win7 SP1 64位旗舰版&#xff1b; 2、按WinR打开运行&#xff0c;输入regedit打开注册表编辑器&#xff0c;定位到HKEY_LOCAL_MACHINE\Software\Microso…

JPA criteria 查询:类型安全与面向对象

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 JPA的标准查询,名为:JPA criteria查询. 相比JPQL,其优势是类型安全,更加的面向对象.使用标准查询,开发人员可在编译的时候就检查 查询的…

Algs4-1.4.18数组的局部最小元素

1.4.18数组的局部最小元素。编写一个程序&#xff0c;给定一个含有N个不同整数的数组&#xff0c;找到一个局部最小元素:满足a[i]<a[i-1],且a[i]<a[i1]的索引i。程序在最坏情况下所需的比较次数为~2lgN。答&#xff1a;检查数组的中间值a[N/2]以及和它相邻的元素a[N/2-1]…

编程技能和做员工的技能——哪个更重要?

摘要&#xff1a;不管我们程序员如何认识这个问题&#xff0c;如果你想在给别人编程打工中获得事业成功&#xff0c;编程技能不是第一重要的。学会如何做一个好的员工才是重要的&#xff0c;甚至是非常重要的。从最最基本的层面上讲&#xff0c;每个员工都应该为最求两种基本的…

nginx-exporter安装使用

一、没有vts的启动方式 #nginx_exporter -telemetry.address:9113 -nginx.scrape_uri"http://127.0.0.1:10000/nginx_statusnginx_exporter -telemetry.address:9113 -nginx.scrape_uri"https://xx.xx.xx.xx:18443" -insecure #端口9113应该是nginx_exporter监…

spring data jpa 的 in 查询 Specification 实现

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 只是一个简单需求&#xff1a; 查询所有部门id 属于 idList 的数据 Page<WorkWeight> page workWeightRepository.findAll(new…

在移动互联网上赚钱,行不行

移动互联网已被证实是互联网产业发展的大趋势。不过&#xff0c;究竟如何赚钱&#xff0c;对海外企业与中国企业来说都是难题。本月初&#xff0c;几位业界大佬与风投来了一番讨论&#xff0c;议题还是一个“在移动互联网上赚钱&#xff0c;行还是不行”。 百度试图通过用户习惯…

计算机网络知识简单介绍

一、网络基础 1.网络指的是什么&#xff1f; 计算机与计算机之间通过物理链接介质&#xff08;网络设备&#xff09;连接到一起。 计算机与计算机之间基于网络协议通信&#xff08;网络协议就相当于计算机界的英语&#xff09; 2.osi七层协议&#xff1a; 互联网协议按照功能不…

Linux下安装FFmpeg

FFmpeg官网&#xff1a;http://www.ffmpeg.org 官网介绍 FFmpeg is the leading multimedia framework, able to decode, encode, transcode, mux, demux, stream, filter and play pretty much anything that humans and machines have created. It supports the most obscure…

HTTP协议状态码详解

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 状态码含义100客户端应当继续发送请求。这个临时响应是用来通知客户端它的部分请求已经被服务器接收&#xff0c;且仍未被拒绝。客户端应…

【Python web 开发】viewset 实现商品详情页的接口

我们如何来完成商品详情页的接口呢&#xff1f; 首先要配置一个商品详情的url 按照我们正常的接口配法 &#xff0c;应该是后面要加一个id 的&#xff0c;为什么这里没有加id 呢? ,应该是rooter register 的作用吧&#xff0c;等我在学习一遍基础再来回答&#xff1f; 那么我…

Ignite中的机器学习介绍

为什么80%的码农都做不了架构师&#xff1f;>>> 本系列共6篇文章&#xff0c;会通过一些代码示例&#xff0c;讲解如何在Ignite中使用机器学习库&#xff0c;本文是本系列的第一篇。 从Ignite的2.4版本开始&#xff0c;机器学习就可以用于生产环境了。在这个版本中…

4G发牌或提早 电信联通面临艰难抉择

曾几何时遥不可及的4G&#xff0c;上马的时间可能要比预期来的要早。今年3月&#xff0c;工信部部长苗圩表示&#xff0c;预计国内需要2-3年才会发放4G牌照。话音犹在耳&#xff0c;苗圩部长9月11日表示&#xff0c;“工信部已决定将于一年左右的时间发放TD-LTE牌照”。 工信部…

mysql 的 sql 执行计划详解

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 引言&#xff1a; 实际项目开发中&#xff0c;由于我们不知道实际查询的时候数据库里发生了什么事情&#xff0c;数据库软件是怎样扫描…

2018-10-28

我的博客即将入驻“云栖社区”&#xff0c;诚邀技术同仁一同入驻。