關(guān)于Feign調(diào)用服務(wù)Headers傳參問題
Feign調(diào)用服務(wù)Headers傳參
在使用springcloud中經(jīng)常會(huì)出現(xiàn)個(gè)服務(wù)調(diào)用,一般情況下會(huì)在Headers加上token的驗(yàn)證,那么在feign調(diào)用時(shí)候我們?cè)趺慈鬟@個(gè)token過去呢,有人會(huì)用@Headers這個(gè)注解來實(shí)現(xiàn)。但是這樣方法太多笨重。
我們可以使用RequestInterceptor來實(shí)現(xiàn)
附上代碼
?? ?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設(shè)置Header頭部,@Headers無效
在使用FeignClient調(diào)用外部接口的時(shí)候,需要在請(qǐng)求頭部添加header的參數(shù),用于請(qǐng)求的認(rèn)證。在查找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);
}在服務(wù)端獲取不到Inner_token的頭部參數(shù)。得到的結(jié)果是null
于是開啟feign的日志
第一步:定義feign的日志配置文件類
@Configuration
public class FeignConfig {
@Bean
Logger.Level feignLevel(){
return Logger.Level.FULL;
}
}第二步:在調(diào)用的FeignClien客戶端注解上指定該日志級(jí)別配置文件
@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的配置路徑和日志級(jí)別
logging:
level:
demo.IUserService: debug重啟,并發(fā)起請(qǐng)求
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ā)現(xiàn),header中沒有被加上我之前設(shè)置的參數(shù)。說明該注解沒有生效
于是debug調(diào)試
通過debug我發(fā)現(xiàn)feign會(huì)先將請(qǐng)求參數(shù)構(gòu)建成Request對(duì)象,request信息如下:

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

到這里可以看出,問題是出在RequestTemplate的構(gòu)建構(gòu)成中,于是我就去跟蹤RequestTemplate構(gòu)建的代碼,發(fā)現(xiàn)RequestTemplate是根據(jù)MethodMetadata構(gòu)建而成,而MethodMetadata就是對(duì)方法配置的抽象。
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的設(shè)置是由metadata的headerMapIndex 屬性決定的,那么,設(shè)置headerMapIndex的位置,必然就和Header的解析相關(guān),于是通過查看方法引用,我找到了下面的代碼:
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需要用“=”進(jìn)行分割。
于是我修改成下面的形式,問題就解決了:
@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);
}查看請(qǐng)求日志
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)
請(qǐng)求中header已經(jīng)被成功添加
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
java隨機(jī)生成字符串(字符隨機(jī)生成類 生成隨機(jī)字符組合)
java隨機(jī)生成字符串,字符組合多樣,可以大小字組合、大+小字符+數(shù)字等方式,大家參考使用吧2013-12-12
Spring中異步注解@Async的使用、原理及使用時(shí)可能導(dǎo)致的問題及解決方法
這篇文章主要介紹了Spring中異步注解@Async的使用、原理及使用時(shí)可能導(dǎo)致的問題及解決方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-07-07
Spring Boot Hazelcast Caching 使用和配置詳解
這篇文章主要介紹了Spring Boot Hazelcast Caching 使用和配置詳解,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-09-09
Java基礎(chǔ)之三大控制流程結(jié)構(gòu)
這篇文章主要介紹了Java基礎(chǔ)之三大控制流程結(jié)構(gòu),文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java基礎(chǔ)的小伙伴們有非常好的幫助,需要的朋友可以參考下2021-04-04
解決SpringBoot使用@Value獲取不到y(tǒng)aml中配置值的問題
在最近的開發(fā)中遇到一個(gè)問題,使用@Value獲取yml文件中配置的屬性時(shí)始終獲取不到值,所以本文給大家詳細(xì)介紹了SpringBoot使用@Value獲取不到y(tǒng)aml中值的問題分析及解決方法,需要的朋友可以參考下2024-01-01
Idea使用插件實(shí)現(xiàn)逆向工程搭建SpringBoot項(xiàng)目的圖文教程
這篇文章主要介紹了Idea使用插件實(shí)現(xiàn)逆向工程搭建SpringBoot項(xiàng)目,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-06-06
springboot+mybatis快速插入大量數(shù)據(jù)的具體實(shí)現(xiàn)
最近導(dǎo)入表格數(shù)據(jù)時(shí)需要同時(shí)插入修改大量數(shù)據(jù),下面這篇文章主要給大家介紹了關(guān)于springboot+mybatis快速插入大量數(shù)據(jù)的具體實(shí)現(xiàn),文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-04-04

