Spring Cloud的Feign客戶端入門
在本教程中,我們將瞭解FeignClient以及如何在Spring Boot/Spring Cloud應用程式中使用它。
FeignClient是一個以宣告方式建立REST API客戶端的庫。因此,如果我們不是手動編寫遠端API客戶端,就可能使用Springs RestTemplate,而使用Feign宣告客戶端定義很方便,其餘部分在執行時生成供使用。
我們將構建一個小型命令列應用程式,它模擬我們一個看板API的完整測試。示例應用程式將建立一個新使用者,登入,檢索所有板並再次登出使用者。它捕獲了最常見的用例(POST,GET,DELETE + AuthN)
新增依賴項
我們在本教程中使用Maven。由於我們不想弄亂版本號,最簡單的方法是在Maven POM 中的dependencyManagement中包含Spring Cloud設定。
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Finchley.SR1</version> <type>pom</type> <scope><b>import</b></scope> </dependency> </dependencies> </dependencyManagement>
現在,我們可以使用經典的Spring Boot啟動程式將依賴項新增到Feign:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
Feign客戶端使用宣告方法來訪問API。要使用它,我們必須首先在我們的Spring Boot應用程式上使用@EnableFeignClients註解啟用Spring Cloud支援。
@SpringBootApplication @EnableFeignClients <b>public</b> <b>class</b> FeignIntroductionApplication implements ApplicationRunner { <font><i>//omitted </i></font><font> } </font>
下一步是宣告用於訪問我們的API的介面。我們將其命名為KanbanClient,因為它將提供呼叫遠端API的方法。
@FeignClient(name=<font>"KanbanClient"</font><font>, url= </font><font>"https://kanbanbackend.herokuapp.com/"</font><font>) <b>public</b> <b>interface</b> KanbanClient { } </font>
要將其轉換為Feign客戶端,我們必須在介面上設定@FeignClient註釋,併為其指定名稱屬性,並使用url屬性設定遠端URL 。這裡支援SpEL,因此我們可以將值外部化為屬性檔案。我們也可以使用Eureka在這裡使用服務發現,而不是使用URL,如果使用Eureka服務發現,這裡只要:
@FeignClient(<font>"KanbanApp"</font><font>) </font>
KanbanApp是註冊在Eureka服務註冊器裡面的應用名稱,也就是對方生產者Srping.application.name=KanbanApp中配置的名稱。
下面要定義遠端呼叫的各個方法,不同遠端API對應不同的介面方法,需要使用Spring MVC中的一些註釋,這些註釋通常也是用在REST伺服器端的@Controller上。它們的行為相同,這裡只是用在REST客戶端。
POST
在方法上新增@PostMapping批註並在其中傳遞引數,將該方法轉換為POST呼叫。在PostMapping註釋中,我們提供了相對於在@FeignClient註釋上設定的URL的端點(具體URL路徑)。
@PostMapping(value = <font>"/register"</font><font>) String registerUser(User user); </font>
使用者是一個簡單的POJO,帶有使用者名稱和密碼欄位。Feign,Spring會自動將其轉換為JSON。
GET
原理與上面相同,但我們在方法上使用@GetMapping。我們還發送了身份驗證標頭。API使用X-Auth-Token。
@GetMapping(<font>"/boards"</font><font>) List<Board> listBoards( @RequestHeader(</font><font>"X-Auth-Token"</font><font>) String authHeader ); </font>
/boards將返回使用者的所有看板板的列表。Board是POJO,僅包含id和name。
PUT
同樣,這次只需使用@PutMapping註釋。
@PutMapping(<font>"/board/{id}"</font><font>) Board changeBoard( @RequestHeader(</font><font>"X-Auth-Token"</font><font>) String authHeader, @PathVariable(</font><font>"id"</font><font>) Long id, Board board ); </font>
我們可以通過將PUT提交看板的端點(/ board / {id})實現更改看板的名稱。路徑變數請參見下面的使用變數進行呼叫部分。
DELETE
只需要@DeleteMapping註釋。
@DeleteMapping(<font>"/unregister"</font><font>) ResponseEntity<Void> unregisterUser( @RequestHeader(</font><font>"X-Auth-Token"</font><font>) String authToken, Confirmation user ); </font>
此端點需要具有使用者密碼的Confirmation物件才能刪除該帳戶,並且如果成功則還需要返回200。
使用變數進行呼叫
如果我們的端點需要基於像ids這樣的實體的變數,我們可以在方法引數上使用@PathVariable註釋。它的行為與Spring MVC @Controllers相同。
然後可以在@PutMapping的端點宣告中使用已定義的變數如:
@PutMapping(<font>"/board/{id}"</font><font>) Board changeBoard( @RequestHeader(</font><font>"X-Auth-Token"</font><font>) String authHeader, @PathVariable(</font><font>"id"</font><font>) Long id, Board board ); </font>
通過身份認證呼叫
我們將使用登入端點。它要求使用者憑據作為基本身份驗證傳送,並將返回令牌以進行進一步身份驗證。當我們成功呼叫/ login端點時,它將在響應頭中返回auth令牌:
@PostMapping(<font>"/login"</font><font>) ResponseEntity<Void> loginUser( @RequestHeader(</font><font>"Authorization"</font><font>) String authHeader ); </font>
向下傳遞附加資訊的第一種方法是在其上新增帶有@RequestHeader註釋的方法引數。引數的值將設定為註釋中定義的HTTP標頭的值。
在身份認證的情況下,它是Authorization標頭。作為一個值,我們給它基本的auth編碼字串。
在隨後的Kanban API呼叫中,我們將使用帶有令牌的X-Auth-Token標頭。
響應頭不能作為方法返回值直接返回,但我們可以使用Spring的ResponseEntity,它是一個響應包裝器。由於我們的端點不會在響應主體中返回任何內容,因此需要將Void作為引數化型別。
當在看板API中使用Spring Session時,需要通過X-Auth-Token標頭交換auth令牌。
要檢索我們呼叫的值:
String token = response.getHeaders().getFirst(<font>"X-Auth-Token"</font><font>); </font>
其他認證方法
我們總是可以在每個方法上使用@RequestHeader註釋傳遞身份驗證標頭。但是,還有一種在全域性範圍內指定的替代方法。
像Spring MVC一樣,Feign有一個攔截器概念,可用於在遠端呼叫之前執行特定的操作。入口點是RequestInterceptor介面。
使用Spring,我們只需要提供一個Bean來實現Spring上下文的特定介面,它將自動被使用。
@Bean AuthInterceptor authFeign() { <b>return</b> <b>new</b> AuthInterceptor(); } <b>class</b> AuthInterceptor implements RequestInterceptor { @Override <b>public</b> <b>void</b> apply(RequestTemplate template) { template.header(<font>"Authorization"</font><font>, </font><font>"<your token>"</font><font>); } } </font>
我們的攔截器是一個Spring Bean,因此我們可以使用Spring的強大功能並將authN資訊外部化為屬性,甚至可以從會話範圍的bean中檢索它,我們會根據每個使用者來儲存資訊。
使用FeignClient
現在,我們可以像任何其他Spring Bean一樣將KanbanClient注入我們的程式碼中。在啟動時,Spring Cloud將為我們設定Feign客戶端併為我們提供常規的Spring Proxy,以便我們可以簡單地開始使用遠端端。
我們使用Feign的客戶端程式碼最終看起來像這樣:
@FeignClient(name=<font>"KanbanClient"</font><font>, url= </font><font>"https://kanbanbackend.herokuapp.com/"</font><font>) <b>public</b> <b>interface</b> KanbanClient { @PostMapping(value = </font><font>"/register"</font><font>) String registerUser(User user); @DeleteMapping(</font><font>"/unregister"</font><font>) ResponseEntity<Void> unregisterUser( @RequestHeader(</font><font>"X-Auth-Token"</font><font>) String authToken, Confirmation user ); @PostMapping(</font><font>"/login"</font><font>) ResponseEntity<Void> loginUser( @RequestHeader(</font><font>"Authorization"</font><font>) String authHeader ); @GetMapping(</font><font>"/boards"</font><font>) List<Board> listBoards( @RequestHeader(</font><font>"X-Auth-Token"</font><font>) String authHeader ); @PostMapping(</font><font>"/boards"</font><font>) Board createBoard( @RequestHeader(</font><font>"X-Auth-Token"</font><font>) String authHeader, Board board ); @PutMapping(</font><font>"/board/{id}"</font><font>) Board changeBoard( @RequestHeader(</font><font>"X-Auth-Token"</font><font>) String authHeader, @PathVariable(</font><font>"id"</font><font>) Long id, Board board ); } </font>