關于Feign調用服務Headers傳參問題
Feign調用服務Headers傳參
在使用springcloud中經常會出現個服務調用,一般情況下會在Headers加上token的驗證,那么在feign調用時候我們怎么去傳這個token過去呢,有人會用@Headers這個注解來實現。但是這樣方法太多笨重。
我們可以使用RequestInterceptor來實現
附上代碼
?? ?import feign.RequestInterceptor;
?? ?import feign.RequestTemplate;
?? ?import org.springframework.stereotype.Component;
?? ?import org.springframework.web.context.request.RequestContextHolder;
?? ?import org.springframework.web.context.request.ServletRequestAttributes;
?? ?import javax.servlet.http.HttpServletRequest;
?? ?import java.util.Enumeration;
?? ?@Component
?? ?public class SecuringRequestInterceptor implements RequestInterceptor {
?? ? ? ?@Override
?? ? ? ?public void apply(RequestTemplate requestTemplate) {
?? ? ? ? ? ?ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
?? ? ? ? ? ? ? ? ? ?.getRequestAttributes();
?? ? ? ? ? ?HttpServletRequest request = attributes.getRequest();
?? ? ? ? ? ?Enumeration<String> headerNames = request.getHeaderNames();
?? ? ? ? ? ?if (headerNames != null) {
?? ? ? ? ? ? ? ?while (headerNames.hasMoreElements()) {
?? ? ? ? ? ? ? ? ? ?String name = headerNames.nextElement();
?? ? ? ? ? ? ? ? ? ?String values = request.getHeader("Ttoken");
?? ? ? ? ? ? ? ? ? ?requestTemplate.header("Ttoken", values);
?? ? ? ? ? ? ? ?}
?? ? ? ? ? ?}
?? ? ? ?}
?? ?}Feign設置Header頭部,@Headers無效
在使用FeignClient調用外部接口的時候,需要在請求頭部添加header的參數,用于請求的認證。在查找Feign文檔中提供了@Headers注解,該注解可以完成頭部的添加。但是卻沒有生效
@FeignClient(name="name",url = "127.0.0.1:8090/test",path = "/")
public interface IUserService {
@RequestMapping(value = "getUserPage",method = RequestMethod.POST)
@Headers(value={"ContentType=application/x-www-form-urlencoded","Inner_token=PXH0dP5I8qQ8UbFPpzm67cQkm7j8tWT2Kwn6J6SXYkfp2kMo/lSqHQ=="})
public Map<String,Object> getUserPage(User user);
}在服務端獲取不到Inner_token的頭部參數。得到的結果是null
于是開啟feign的日志
第一步:定義feign的日志配置文件類
@Configuration
public class FeignConfig {
@Bean
Logger.Level feignLevel(){
return Logger.Level.FULL;
}
}第二步:在調用的FeignClien客戶端注解上指定該日志級別配置文件
@FeignClient(name="name",url = "127.0.0.1:8090/test",path = "/",configuration = FeignConfig.class)
public interface IUserService {
@RequestMapping(value = "getUserPage",method = RequestMethod.POST)
@Headers(value={"ContentType=application/x-www-form-urlencoded","Inner_token=PXH0dP5I8qQ8UbFPpzm67cQkm7j8tWT2Kwn6J6SXYkfp2kMo/lSqHQ=="})
public Map<String,Object> getUserPage(User user);
}第三步:配置yml文件,指定該feignclient的配置路徑和日志級別
logging:
level:
demo.IUserService: debug重啟,并發(fā)起請求
2019-09-27 10:46:01.662 DEBUG 15200 --- [ hystrix-name-1] demo.IUserService : [IUserService#getUserPage] ---> POST http://127.0.0.1:8090/test/getUserPage HTTP/1.1
2019-09-27 10:46:01.663 DEBUG 15200 --- [ hystrix-name-1] demo.IUserService : [IUserService#getUserPage] Content-Type: application/json;charset=UTF-8
2019-09-27 10:46:01.663 DEBUG 15200 --- [ hystrix-name-1] demo.IUserService : [IUserService#getUserPage] Content-Length: 53
2019-09-27 10:46:01.663 DEBUG 15200 --- [ hystrix-name-1] demo.IUserService : [IUserService#getUserPage]
2019-09-27 10:46:01.663 DEBUG 15200 --- [ hystrix-name-1] demo.IUserService : [IUserService#getUserPage] {"id":0,"tableName":"feignTable","page":10,"size":10}
2019-09-27 10:46:01.663 DEBUG 15200 --- [ hystrix-name-1] demo.IUserService : [IUserService#getUserPage] ---> END HTTP (53-byte body)
2019-09-27 10:46:01.684 DEBUG 15200 --- [ hystrix-name-1] demo.IUserService : [IUserService#getUserPage] <--- HTTP/1.1 200 (21ms)
2019-09-27 10:46:01.684 DEBUG 15200 --- [ hystrix-name-1] demo.IUserService : [IUserService#getUserPage] content-type: application/json;charset=UTF-8
2019-09-27 10:46:01.685 DEBUG 15200 --- [ hystrix-name-1] demo.IUserService : [IUserService#getUserPage] date: Fri, 27 Sep 2019 02:46:01 GMT
2019-09-27 10:46:01.685 DEBUG 15200 --- [ hystrix-name-1] demo.IUserService : [IUserService#getUserPage] transfer-encoding: chunked
2019-09-27 10:46:01.685 DEBUG 15200 --- [ hystrix-name-1] demo.IUserService : [IUserService#getUserPage] x-application-context: HelloServer:8090
2019-09-27 10:46:01.685 DEBUG 15200 --- [ hystrix-name-1] demo.IUserService : [IUserService#getUserPage]
2019-09-27 10:46:01.689 DEBUG 15200 --- [ hystrix-name-1] demo.IUserService : [IUserService#getUserPage] {"success":true,"rows":[{"id":10111,"tableName":"hbaseTable","page":1,"size":20},{"id":10112,"tableName":"hbaseTable","page":1,"size":20},{"id":10113,"tableName":"hbaseTable","page":1,"size":20},{"id":10114,"tableName":"hbaseTable","page":1,"size":20},{"id":10115,"tableName":"hbaseTable","page":1,"size":20},{"id":10116,"tableName":"hbaseTable","page":1,"size":20},{"id":10117,"tableName":"hbaseTable","page":1,"size":20},{"id":10118,"tableName":"hbaseTable","page":1,"size":20},{"id":10119,"tableName":"hbaseTable","page":1,"size":20},{"id":10120,"tableName":"hbaseTable","page":1,"size":20}]}
2019-09-27 10:46:01.689 DEBUG 15200 --- [ hystrix-name-1] demo.IUserService : [IUserService#getUserPage] <--- END HTTP (595-byte body)
在日志中發(fā)現,header中沒有被加上我之前設置的參數。說明該注解沒有生效
于是debug調試
通過debug我發(fā)現feign會先將請求參數構建成Request對象,request信息如下:

從圖中可看到,該Request實例的headers屬性為空,而Request又是根據RequestTemplate模板對象生成的,RequestTemplate實例信息如下:

到這里可以看出,問題是出在RequestTemplate的構建構成中,于是我就去跟蹤RequestTemplate構建的代碼,發(fā)現RequestTemplate是根據MethodMetadata構建而成,而MethodMetadata就是對方法配置的抽象。
RequestTemplate template = resolve(argv, mutable, varBuilder);
if (metadata.queryMapIndex() != null) {
// add query map parameters after initial resolve so that they take
// precedence over any predefined values
template = addQueryMapQueryParameters(argv, template);
}
if (metadata.headerMapIndex() != null) {
template = addHeaderMapHeaders(argv, template);
}從上述代碼可以看到,header的設置是由metadata的headerMapIndex 屬性決定的,那么,設置headerMapIndex的位置,必然就和Header的解析相關,于是通過查看方法引用,我找到了下面的代碼:
private void parseHeaders(MethodMetadata md, Method method,
RequestMapping annotation) {
// TODO: only supports one header value per key
if (annotation.headers() != null && annotation.headers().length > 0) {
for (String header : annotation.headers()) {
int index = header.indexOf('=');
if (!header.contains("!=") && index >= 0) {
md.template().header(resolve(header.substring(0, index)),
resolve(header.substring(index + 1).trim()));
}
}
}
}從代碼中我們可以清晰的看到,解析過程中是從@RequestMapping或其派生注解的header屬性中解析Header的,并且Header的key和value需要用“=”進行分割。
于是我修改成下面的形式,問題就解決了:
@FeignClient(name="name",url = "127.0.0.1:8090/test",path = "/",configuration = FeignConfig.class)
public interface IUserService {
@RequestMapping(value = "getUserPage",method = RequestMethod.POST,headers = {"ContentType=application/x-www-form-urlencoded","Inner_token=PXH0dP5I8qQ8UbFPpzm67cQkm7j8tWT2Kwn6J6SXYkfp2kMo/lSqHQ=="})
@Headers(value={"ContentType=application/x-www-form-urlencoded","Inner_token=PXH0dP5I8qQ8UbFPpzm67cQkm7j8tWT2Kwn6J6SXYkfp2kMo/lSqHQ=="})
public Map<String,Object> getUserPage(User user);
}查看請求日志
2019-09-27 11:10:29.975 DEBUG 8604 --- [ hystrix-name-1] demo.IUserService : [IUserService#getUserPage] ---> POST http://127.0.0.1:8090/test/getUserPage HTTP/1.1
2019-09-27 11:10:29.976 DEBUG 8604 --- [ hystrix-name-1] demo.IUserService : [IUserService#getUserPage] ContentType: application/x-www-form-urlencoded
2019-09-27 11:10:29.976 DEBUG 8604 --- [ hystrix-name-1] demo.IUserService : [IUserService#getUserPage] Inner_token: PXH0dP5I8qQ8UbFPpzm67cQkm7j8tWT2Kwn6J6SXYkfp2kMo/lSqHQ==
2019-09-27 11:10:29.976 DEBUG 8604 --- [ hystrix-name-1] demo.IUserService : [IUserService#getUserPage] Content-Type: application/json;charset=UTF-8
2019-09-27 11:10:29.976 DEBUG 8604 --- [ hystrix-name-1] demo.IUserService : [IUserService#getUserPage] Content-Length: 53
2019-09-27 11:10:29.976 DEBUG 8604 --- [ hystrix-name-1] demo.IUserService : [IUserService#getUserPage]
2019-09-27 11:10:29.976 DEBUG 8604 --- [ hystrix-name-1] demo.IUserService : [IUserService#getUserPage] {"id":0,"tableName":"feignTable","page":10,"size":10}
2019-09-27 11:10:29.976 DEBUG 8604 --- [ hystrix-name-1] demo.IUserService : [IUserService#getUserPage] ---> END HTTP (53-byte body)
2019-09-27 11:10:29.992 DEBUG 8604 --- [ hystrix-name-1] demo.IUserService : [IUserService#getUserPage] <--- HTTP/1.1 200 (16ms)
2019-09-27 11:10:29.993 DEBUG 8604 --- [ hystrix-name-1] demo.IUserService : [IUserService#getUserPage] content-type: application/json;charset=UTF-8
2019-09-27 11:10:29.993 DEBUG 8604 --- [ hystrix-name-1] demo.IUserService : [IUserService#getUserPage] date: Fri, 27 Sep 2019 03:10:29 GMT
2019-09-27 11:10:29.993 DEBUG 8604 --- [ hystrix-name-1] demo.IUserService : [IUserService#getUserPage] transfer-encoding: chunked
2019-09-27 11:10:29.993 DEBUG 8604 --- [ hystrix-name-1] demo.IUserService : [IUserService#getUserPage] x-application-context: HelloServer:8090
2019-09-27 11:10:29.993 DEBUG 8604 --- [ hystrix-name-1] demo.IUserService : [IUserService#getUserPage]
2019-09-27 11:10:29.995 DEBUG 8604 --- [ hystrix-name-1] demo.IUserService : [IUserService#getUserPage] {"success":true,"rows":[{"id":10141,"tableName":"hbaseTable","page":1,"size":20},{"id":10142,"tableName":"hbaseTable","page":1,"size":20},{"id":10143,"tableName":"hbaseTable","page":1,"size":20},{"id":10144,"tableName":"hbaseTable","page":1,"size":20},{"id":10145,"tableName":"hbaseTable","page":1,"size":20},{"id":10146,"tableName":"hbaseTable","page":1,"size":20},{"id":10147,"tableName":"hbaseTable","page":1,"size":20},{"id":10148,"tableName":"hbaseTable","page":1,"size":20},{"id":10149,"tableName":"hbaseTable","page":1,"size":20},{"id":10150,"tableName":"hbaseTable","page":1,"size":20}]}
2019-09-27 11:10:29.995 DEBUG 8604 --- [ hystrix-name-1] demo.IUserService : [IUserService#getUserPage] <--- END HTTP (595-byte body)
請求中header已經被成功添加
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
JAVA?Springboot配置i18n國際化語言詳細步驟
國際化(Internationalization,縮寫為i18n)是指根據來展示不同的內容,使應用程序能夠適應不同的語言和文化習慣,下面這篇文章主要給大家介紹了關于JAVA?Springboot配置i18n國際化語言的詳細步驟,需要的朋友可以參考下2024-08-08
SpringBoot2.7?WebSecurityConfigurerAdapter類過期配置
這篇文章主要為大家介紹了SpringBoot2.7中WebSecurityConfigurerAdapter類過期應該如何配置,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-06-06

