Feign如何實(shí)現(xiàn)第三方的HTTP請(qǐng)求
最近,在使用spring cloud框架時(shí),發(fā)現(xiàn)feign也能實(shí)現(xiàn)三方請(qǐng)求,而且實(shí)現(xiàn)很簡(jiǎn)單,請(qǐng)求接口的結(jié)構(gòu)很清晰,便果斷學(xué)習(xí)一波。
記錄一下。本次使用的依賴僅有openfeign。
Feign調(diào)用的簡(jiǎn)單實(shí)現(xiàn)
maven依賴
<!-- openfeign依賴 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
Feign配置方式
feign有三種使用方式,前一種多是用于無(wú)需配置的微服務(wù)內(nèi)部調(diào)用,后兩者是用于自定義配置的三方調(diào)用或者內(nèi)部微服務(wù)調(diào)用。
1. 默認(rèn)模式,不使用配置類(lèi),作用于服務(wù)內(nèi)部調(diào)用而非三方請(qǐng)求接口
這種情況下,如果不需要給注冊(cè)中心的微服務(wù)添加額外的參數(shù)配置,那么可以不使用配置類(lèi),直接在yml配置打開(kāi)feign開(kāi)關(guān)即可。
此時(shí)默認(rèn)使用SpringMVC契約模式。如下代碼中,yml配置為用戶中心的配置文件。
如果一個(gè)業(yè)務(wù)中心想要根據(jù)用戶id查詢用戶信息,那么便可以直接根據(jù)用戶中心的服務(wù)名定位,如UserService 類(lèi)中的@FeignClient配置,注冊(cè)中心會(huì)自動(dòng)根據(jù)服務(wù)名尋址到用戶中心的地址。
# 用戶中心的服務(wù)名 spring: application: name: user-service # 注冊(cè)中心 eureka: instance: prefer-ip-address: true hostname: localhost client: service-url: defaultZone: http://localhost:8080/eureka/ # feign feign: httpclient: enabled: true
@FeignClient(name = "user-service", fallback = UserServiceHystrix.class) public interface UserService { @GetMapping("/user/getUserById") Result getUserById(@RequestParam("id") String id); }
2.自定義配置類(lèi)
自定義配置類(lèi)時(shí), 直接在feign的配置類(lèi)上加@Configuration注解,該注解的方式是全局的,對(duì)于所有由@FeignClient注解的調(diào)用類(lèi)都生效。
這樣的好處在于,調(diào)用項(xiàng)目注冊(cè)中心的其他服務(wù)時(shí)不用頻繁的手動(dòng)去加載配置類(lèi)。該配置類(lèi)也會(huì)被加載到spring cloud feign的服務(wù)調(diào)用中。
不過(guò),比較致命的是,調(diào)用外部API時(shí)有可能會(huì)和微服務(wù)調(diào)用之間產(chǎn)生沖突。
Feign契約不支持SpringMVC契約,在feign契約下使用springMVC注解時(shí),spring注解的部分功能會(huì)失效,甚至導(dǎo)致創(chuàng)建bean失敗等。
(大部分java.lang.IllegalStateException: Method getAllUrl not annotated with HTTP method type (ex. GET, POST) 異常都是由于契約問(wèn)題造成的。)
3.自定義配置類(lèi)法2
自定義配置類(lèi)時(shí),另一種則是不使用注解對(duì)配置類(lèi)加以標(biāo)識(shí),而是在@FeignClient的注解中添加配置參數(shù),在需要調(diào)用外部API接口的feign調(diào)用類(lèi)里手動(dòng)加載該配置,加載方式如后文中ApiService服務(wù)所示。
使用這種方式能將項(xiàng)目同注冊(cè)中心的服務(wù)與外部API區(qū)分開(kāi)來(lái)。
但是需要每一個(gè)feign類(lèi)去手動(dòng)加載該配置。@FeignClient參數(shù)會(huì)在下文中講到。
4. @FeignClient參數(shù)說(shuō)明
@FeignClient用來(lái)修飾類(lèi)、接口類(lèi)、注解類(lèi)等。它的所有參數(shù)如下:
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface FeignClient { @AliasFor("name") String value() default ""; /** @deprecated */ @Deprecated String serviceId() default ""; String contextId() default ""; @AliasFor("value") String name() default ""; String qualifier() default ""; String url() default ""; boolean decode404() default false; Class<?>[] configuration() default {}; Class<?> fallback() default void.class; Class<?> fallbackFactory() default void.class; String path() default ""; boolean primary() default true; }
value
:服務(wù)名,訪問(wèn)第三方接口時(shí)可以隨便命名。支持從配置文件中獲取配置。name
:請(qǐng)求的服務(wù)名(用于微服務(wù)時(shí),請(qǐng)求其他服務(wù)名的名稱)。url
:第三方請(qǐng)求地址,支持從配置文件中獲取配置。fallback
:失敗時(shí)請(qǐng)求的回調(diào)類(lèi),熔斷處理。configuration
:手動(dòng)加載feign配置類(lèi)。
5. 自定義配置的簡(jiǎn)單實(shí)現(xiàn)
A. Feign配置類(lèi)
// 增加該配置時(shí),該配置類(lèi)就變成全局配置類(lèi) // @Configuration public class FeignConfig implements RequestInterceptor { @Autowired private ObjectFactory<HttpMessageConverters> messageConverters; @Bean public Contract feignContract() { // feign 契約 @RequestLine return new Contract.Default(); // springMVC契約 @GetMapping @PostMapping 等 // return new SpringMvcContract(); } // 記錄請(qǐng)求和響應(yīng)的頭文件,正文和元數(shù)據(jù)的日志,需要在配置文件指出需要打印日志的類(lèi) @Bean Logger.Level feignLoggerLevel() { return Logger.Level.FULL; } // 連接超時(shí)時(shí)間說(shuō)明:連接超時(shí)時(shí)間,單位分鐘,讀取超時(shí)時(shí)間,單位秒,重定向?yàn)槭? @Bean public Options options() { return new Options(10, TimeUnit.MINUTES, 60, TimeUnit.SECONDS, true); } // 編碼方式 @Bean public Encoder feignFormEncoder() { return new SpringFormEncoder(new SpringEncoder(messageConverters)); } // (全局設(shè)置)設(shè)置請(qǐng)求頭等業(yè)務(wù)需要參數(shù)。 @Override public void apply(RequestTemplate template) { } }
B. 配置文件
使用yml文件配置。Feign默認(rèn)使用URLConnection發(fā)送HTTP請(qǐng)求??梢酝ㄟ^(guò)配置文件修改他的http發(fā)送方式如:httpclient、okhttp等??梢愿鶕?jù)自己的需求進(jìn)行修改。
server: port: 8080 #設(shè)置feign請(qǐng)求方式 feign: httpclient: enabled: true # 打開(kāi)debug請(qǐng)求日志 可以使用的參數(shù)有info warn error debug等 logging: level: com.example.feign.feign.ApiService: debug # 第三方請(qǐng)求地址 api: url: https://api.apiopen.top
C. 正式使用,feign無(wú)參數(shù)GET方式 請(qǐng)求三方接口
該部分的測(cè)試接口都是基于開(kāi)源社區(qū)的測(cè)試接口。使用很久了,再次感謝一下開(kāi)源社區(qū)大佬們的幸苦付出?,F(xiàn)在有好多接口都用不了。希望大家不要惡意刷接口。
請(qǐng)求方式:GET
請(qǐng)求地址:https://api.apiopen.top/getSingleJoke
方法上使用的注解是feign契約(Contract)RequestLine。要使用Spring契約 GetMapping 等注解時(shí),需要在FeignConfig中配置即可。
ApiService類(lèi)代碼如下:
@FeignClient(value = "api-service", url = "${api.url}" , fallback = ApiServiceHystrix.class, configuration = FeignConfig.class) public interface ApiService { /** * 平臺(tái)接口預(yù)覽 方法名可以隨便取 */ @RequestLine("GET /getAllUrl") List<String> getAllUrl(); }
ApiServiceHystrix類(lèi)代碼:
public class ApiServiceHystrix implements ApiService { @Override public List<String> getAllUrl() { // 設(shè)置調(diào)用失敗時(shí)的降級(jí)處理 return null; } }
調(diào)用寫(xiě)好的接口,查看參數(shù):
調(diào)用成功!Feign的基礎(chǔ)調(diào)用很簡(jiǎn)單,如果需要調(diào)用多個(gè)相同地址的第三方請(qǐng)求,只需要新增方法即可,無(wú)需再增加額外的配置。
但僅僅用于單次調(diào)用時(shí),feign比起其他HTTP請(qǐng)求方式又稍顯麻煩,不過(guò)勝在簡(jiǎn)潔明了。
6. Feign 的其他請(qǐng)求方式
- Query參數(shù)
請(qǐng)求方式:POST
請(qǐng)求地址:https://api.apiopen.top/getImages
現(xiàn)在嘗試用feign來(lái)進(jìn)行Query請(qǐng)求。請(qǐng)求成功后,用于接收數(shù)據(jù)的對(duì)象可以是一個(gè)Java 對(duì)象類(lèi),也可以是JSONObject對(duì)象。當(dāng)返回內(nèi)容結(jié)構(gòu)穩(wěn)定時(shí)(成功失敗所返回的數(shù)據(jù)格式相同時(shí)),Java對(duì)象才能準(zhǔn)確接收到信息。
創(chuàng)建一個(gè)結(jié)果類(lèi):
@Data public class ApiResult implements Serializable { private static final long serialVersionUID = 1L; private Integer code; private String message; private List result; }
ApiService類(lèi)中增加對(duì)應(yīng)方法:
@RequestLine("POST /getImages?page={page}&count={count}") ApiResult getImages(@Param("page") String page, @Param("count") String count);
請(qǐng)求結(jié)果:
- POST表單
post表單請(qǐng)求發(fā)送時(shí),請(qǐng)求參數(shù)要為Map類(lèi)型的鍵值對(duì)。示例代碼:
@RequestLine("POST /deleteFeedback") ApiResult deleteFeedback(@RequestBody Map<String, ?> bodyMap);
- 設(shè)置Header請(qǐng)求頭
請(qǐng)求頭可以通過(guò)feign注解 @HeaderMap(import feign.HeaderMap;)示例代碼:
@RequestLine("POST /requestHeader") JSONObject getTcText(@HeaderMap Map<String, Object> headers, @RequestBody Map<String, Object> map);
其他請(qǐng)求可移步git:open-feign
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
JAVA Iterator 轉(zhuǎn)成 List 的操作
這篇文章主要介紹了JAVA Iterator 轉(zhuǎn)成 List 的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-12-12intellij idea自動(dòng)生成類(lèi)注釋和方法注釋配置方法
這篇文章主要介紹了intellij idea自動(dòng)生成類(lèi)注釋和方法注釋設(shè)置方法,需要的朋友可以參考下2023-01-01logback.xml動(dòng)態(tài)配置程序路徑的操作
這篇文章主要介紹了logback.xml動(dòng)態(tài)配置程序路徑的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-02-02深入了解SpringBoot中@InitBinder注解的使用
這篇文章主要介紹了深入了解SpringBoot中@InitBinder注解的使用,@InitBinder注解可以作用在被@Controller注解的類(lèi)的方法上,表示為當(dāng)前控制器注冊(cè)一個(gè)屬性編輯器,用于對(duì)WebDataBinder進(jìn)行初始化,且只對(duì)當(dāng)前的Controller有效,需要的朋友可以參考下2023-10-10Java后端向前端返回文件流實(shí)現(xiàn)下載功能
后端可以使用Java中servlet提供的HttpServletResponse,核心步驟是要設(shè)置響應(yīng)的數(shù)據(jù)類(lèi)型,設(shè)置為某一類(lèi)文件類(lèi)型或二進(jìn)制格式,以及響應(yīng)頭,然后用ServletOutputStream將文件以流的形式發(fā)送到前端,本文介紹Java后端向前端返回文件流實(shí)現(xiàn)下載功能,感興趣的朋友一起看看吧2023-12-12JAVA 根據(jù)Url把多文件打包成ZIP下載實(shí)例
這篇文章主要介紹了JAVA 根據(jù)Url把多文件打包成ZIP下載的相關(guān)資料,需要的朋友可以參考下2017-08-08Spring?Cloud詳細(xì)講解zuul集成Eureka流程
這篇文章主要介紹了Spring?Cloud?zuul集成Eureka,Eureka?Client中內(nèi)置一個(gè)負(fù)載均衡器,用來(lái)進(jìn)行基本的負(fù)載均衡,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06mybatis-plus update更新操作的三種方式(小結(jié))
本文主要介紹了mybatis-plus update更新操作的三種方式,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10