springboot中用@FeignClient 調用第三方服務,自定義設置Header


問題描述

在springboot項目中集成Feign訪問第三方服務時,需要在header中設置token,具體操作步驟如下。
在使用@FeignClient之前需要引入的包:

	 	 <!-- spring cloud -->
	    
		<dependency>
		    <groupId>org.springframework.cloud</groupId>
		    <artifactId>spring-cloud-starter</artifactId>
		    <version>3.0.1</version>
		</dependency>

		<dependency>
		    <groupId>org.springframework.cloud</groupId>
		    <artifactId>spring-cloud-context</artifactId>
		     <version>3.0.1</version>
		</dependency>

		<dependency>
		    <groupId>org.springframework.cloud</groupId>
		    <artifactId>spring-cloud-starter-openfeign</artifactId>
		     <version>3.0.1</version>
		</dependency>

需要在啟動類上開啟Feign

@EnableFeignClients
@SpringBootApplication
public class TestApplication {

	public static void main(String[] args) {
		SpringApplication.run(TestApplication.class, args);
	}
}

創建client接口,添加 @Header注解:

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import feign.Headers;
import feign.Param;
import feign.RetryableException;

@FeignClient(value = "testClient", url = "${demo.test.url}")
public interface TestFeignClient {
	
	@RequestMapping(method = RequestMethod.POST, path = "/path")
	@Headers({"Content-Type: application/json","token: {token}"})
	String demo(@RequestBody String request,@Param("token")String token) throws RetryableException;
	
}

查看Feign的@Header文檔如下:


feign.Headers

@Target(value={METHOD, TYPE})
@Retention(value=RUNTIME)

Expands headers supplied in the value. Variables to the the right of the colon areexpanded. 

 @Headers("Content-Type: application/xml")
 interface SoapApi {
 ...   
 @RequestLine("GET /")
 @Headers("Cache-Control: max-age=640000")
 ...

 @RequestLine("POST /")
 @Headers({
   "X-Foo: Bar",
   "X-Ping: {token}"
 }) void post(@Param("token") String token);
 ...
 

Notes: •If you'd like curly braces literally in the header, urlencode them first.
•Headers do not overwrite each other. All headers with the same name will be included in therequest.

Relationship to JAXRS

The following two forms are identical. 

Feign:  @RequestLine("POST /")
 @Headers({
   "X-Ping: {token}"
 }) void post(@Named("token") String token);
 ...
 

JAX-RS:  @POST @Path("/")
 void post(@HeaderParam("X-Ping") String token);
 ...


由於feign的post方式方法中只允許傳入一個@RequestBody,在項目啟動的時候會報錯:

Caused by: java.lang.IllegalStateException: Method has too many Body parameters: public abstract java.lang.String com.demo.TestFeignClient.demo(java.lang.String,java.lang.String) throws feign.RetryableException
Warnings:
- 
	at feign.Util.checkState(Util.java:129) ~[feign-core-10.10.1.jar:na]
	at feign.Contract$BaseContract.parseAndValidateMetadata(Contract.java:127) ~[feign-core-10.10.1.jar:na]
	at org.springframework.cloud.openfeign.support.SpringMvcContract.parseAndValidateMetadata(SpringMvcContract.java:194) ~[spring-cloud-openfeign-core-3.0.1.jar:3.0.1]
	at feign.Contract$BaseContract.parseAndValidateMetadata(Contract.java:62) ~[feign-core-10.10.1.jar:na]
	at feign.ReflectiveFeign$ParseHandlersByName.apply(ReflectiveFeign.java:151) ~[feign-core-10.10.1.jar:na]
	at feign.ReflectiveFeign.newInstance(ReflectiveFeign.java:49) ~[feign-core-10.10.1.jar:na]
	at feign.Feign$Builder.target(Feign.java:269) ~[feign-core-10.10.1.jar:na]
	at org.springframework.cloud.openfeign.DefaultTargeter.target(DefaultTargeter.java:30) ~[spring-cloud-openfeign-core-3.0.1.jar:3.0.1]
	at org.springframework.cloud.openfeign.FeignClientFactoryBean.getTarget(FeignClientFactoryBean.java:359) ~[spring-cloud-openfeign-core-3.0.1.jar:3.0.1]
	at org.springframework.cloud.openfeign.FeignClientFactoryBean.getObject(FeignClientFactoryBean.java:322) ~[spring-cloud-openfeign-core-3.0.1.jar:3.0.1]
	at org.springframework.cloud.openfeign.FeignClientsRegistrar.lambda$registerFeignClient$0(FeignClientsRegistrar.java:224) ~[spring-cloud-openfeign-core-3.0.1.jar:3.0.1]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainFromSupplier(AbstractAutowireCapableBeanFactory.java:1231) ~[spring-beans-5.3.4.jar:5.3.4]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1173) ~[spring-beans-5.3.4.jar:5.3.4]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:564) ~[spring-beans-5.3.4.jar:5.3.4]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524) ~[spring-beans-5.3.4.jar:5.3.4]
	... 29 common frames omitted

這下犯難了,能不能添加屬性到header中先不說,項目都起不起來了,o(╥﹏╥)o
我們來慢慢分析,即使上面的@Header注解使用沒有問題, Method has too many Body parameters的問題也無法跳過。為了不浪費時間,直接看下面的解決方案。

解決方案

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import feign.RetryableException;

@FeignClient(value = "testClient", url = "${demo.test.url}")
public interface TestFeignClient {
    @RequestMapping(method = RequestMethod.POST, path = "/path",headers = {"Content-Type=application/json"})
	String demo(@RequestBody String request,@RequestHeader(name = "token",required = true) String token) throws RetryableException;
}

需要注意的有兩點:
1、設置Header的Content-Type屬性,放在了@RequestMapping中,且格式為 Content-Type=application/json
2、添加驗證token屬性,使用了@RequestHeader注解,把token作為動態參數傳入

重啟項目,縱享絲滑O(∩_∩)O


免責聲明!

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



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