在開發 Spring Cloud 微服務的時候,我們知道,服務之間都是以 HTTP 接口的形式對外提供服務的,因此消費者在進行調用的時候,底層就是通過 HTTP Client 的這種方式進行訪問。當然我們可以使用JDK原生的 URLConnection、Apache 的 HTTP Client、Netty 異步 Http Client,Spring 的 RestTemplate 去實現服務間的調用。但是最方便、最優雅的方式是通過 Spring Cloud Open Feign 進行服務間的調用。Spring Cloud 對 Feign 進行了增強,使 Feign 支持 Spring Mvc 的注解,並整合了 Ribbon 等,從而讓 Feign 的使用更加方便。
Feign是一個聲明式的Web服務客戶端,使用Feign可使得Web服務客戶端的寫入更加方便。 它具有可插拔注釋支持,包括Feign注解和JAX-RS注解、Feign還支持可插拔編碼器和解碼器、Spring Cloud增加了對Spring MVC注釋的支持,並HttpMessageConverters在Spring Web中使用了默認使用的相同方式。Spring Cloud集成了Ribbon和Eureka,在使用Feign時提供負載平衡的http客戶端。
Feign作用:可以解決不同服務器接口之間的相互調用,即跨域請求!feign結合eureka注冊中心,把不同的服務項目注冊到eureka中,通過feign客戶端進行調用,可以解決負載均衡問題。
接下來就簡單講述一下Feign的入門使用
一、引入依賴及配置編寫
1、引入依賴
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-gson</artifactId>
<version>10.2.3</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
2、編寫配置文件
@Configuration public class FeignConfiguration { @Bean public Contract feignContract() { return new Contract.Default(); } @Bean Logger.Level feignLoggerLevel() { return Logger.Level.FULL; } @Bean Decoder feignDecoder() { return new GsonDecoder(); } @Bean Encoder feignEncoder() { return new GsonEncoder(); } }
3、在應用主類Application里,通過@EnableFeignClients注解開啟Spring Cloud Feign的支持功能。
// 在啟動類上加上注解 // 開啟 Feign 掃描支持
@EnableFeignClients
二、編寫Feign接口及使用
1、編寫Feign接口
@FeignClient注解指定服務名來綁定服務,然后再使用Spring MVC的注解來綁定具體該服務提供的REST接口。
@FeignClient(name = "myApi", url = "http://localhost:8080") public interface MyService { // 調用另外一個服務的接口
@RequestLine("GET /getUsers?searchString={searchString}") @Headers("Content-Type: application/json") List<User> getUsers(@Param("searchString") String searchString); }
2、使用接口
Feign接口不需要實現類,可直接調用
private MyService myService; @GetMapping("/userList") public List<User> getUsers(@RequestParam String searchString){ List<User> userList = myService.getUsers(searchString); return userList; }
三、攜帶token請求
為了安全考慮要訪問的服務的接口需要token驗證才能訪問,因此需要攜帶token才能訪問。關於新的服務搭建安全框架,使用與要訪問的平台一致的token生成和驗證機制,這里就不贅述了。
1、方案一:直接在@Headers注解中加token
這種方案可以用來測試,因為,這種方式token是寫死的,不能根據瀏覽器攜帶的token進行驗證。
@FeignClient(name = "myApi", url = "http://localhost:8080") public interface MyService { @RequestLine("GET /getUsers?searchString={searchString}") // 直接在@Headers注解中加token
@Headers({"Content-Type: application/json", "Authorization: Bearer eyJh..."}) List<User> getUsers(@Param("searchString") String searchString); }
2、方案二:根據瀏覽器動態獲取token
如何從瀏覽器中拿到token?
可以看到javax.servlet.http包下有個getHeader的方法,可以獲得當前瀏覽器Header中的信息。
如何將token放到跨域請求中?
在fegin包中的請求攔截器RequestInterceptor有個apply方法,該方法的默認實現如下:
可以看到,默認的Authorization是通過用戶名和密碼進行base64加密得到的,跟我們的token生成方式不一樣,所以直接使用默認的是無法驗證通過的,因此,只需實現RequestInterceptor,重寫apply方法即可
解決方案
編寫配置類,實現RequestInterceptor,重寫apply方法,把瀏覽器header拿到的token放進去。
@Slf4j @Configuration @AllArgsConstructor public class NimBusRequestInterceptor implements RequestInterceptor { private HttpServletRequest req; private static final String HEADER_STRING = "Authorization"; @Override public void apply(RequestTemplate requestTemplate) { // 如果header沒有auth頭,從cookie獲取token
String token = req.getHeader(HEADER_STRING); Cookie[] cookies = req.getCookies(); if (cookies != null && cookies.length > 0) { for (Cookie cookie : cookies) { if (Objects.equals(cookie.getName(), "token")) { try { token = URLDecoder.decode(cookie.getValue(), StandardCharsets.UTF_8.name()); } catch (UnsupportedEncodingException e) { log.error(LogUtil.getStack(e)); } } } } requestTemplate.header(HEADER_STRING, token); } }
以上就實現了Feign基本使用與攜帶token請求。
原文鏈接:https://www.modb.pro/db/32126