服務對外提供接口以供不同站點之間使用:Spring Cloud Feign使用記錄及攜帶token請求


  在開發 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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM