springcloud Feign调用拦截器(统一处理拷贝请求头实现透传信息、内部调用鉴权、打印feign调用日志)
实现接口Feign.RequestInterceptor
实现接口 feign.RequestInterceptor 并注入到IOC容器即可生效
示范代码如下
- 拷贝请求头,将原请求信息透传下去给被调用的feign服务,部分头不拷贝,例如content-length
- 内部调用鉴权标记,在发起feign调用时加上标记(每天一个token,64位随机字符,在redis记录了今天的和昨天的,都有效),让内部调用时有权限调用被调服务
- 打印feign调用目标的日志
/**
* @author humorchen
* date: 2024/5/27
* description: feign 请求拦截器
**/
@Slf4j
public class FeignInterceptor implements RequestInterceptor {
/**
* 跳过某些 header
* 比对时会忽略大小写
*/
private static final Set<String> SKIP_HEADER_NAMES = new HashSet<>(Arrays.asList("transfer-encoding", "content-length", "accept", "accept-encoding", "connection"));
static {
// 转换为小写,避免大小写不一致
HashSet<String> lowCaseSet = new HashSet<>(SKIP_HEADER_NAMES.size());
SKIP_HEADER_NAMES.forEach(name -> lowCaseSet.add(name.toLowerCase()));
SKIP_HEADER_NAMES.clear();
SKIP_HEADER_NAMES.addAll(lowCaseSet);
}
/**
* Called for every request. Add data using methods on the supplied {@link RequestTemplate}.
*
* @param template
*/
@Override
public void apply(RequestTemplate template) {
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
// 拷贝请求头信息,透传信息
if (requestAttributes != null) {
HttpServletRequest request = requestAttributes.getRequest();
Enumeration<String> headerNames = request.getHeaderNames();
if (headerNames != null) {
while (headerNames.hasMoreElements()) {
// 跳过某些 header
String name = headerNames.nextElement();
if (SKIP_HEADER_NAMES.contains(name.toLowerCase())) {
continue;
}
String values = request.getHeader(name);
template.header(name, values);
}
}
}
// 内部调用鉴权标记
template.header(SaSameUtil.SAME_TOKEN, SaSameUtil.getToken());
// 测试环境打印
log.debug("【新版权限日志】FeignInterceptor 发起Feign调用({}),请求头已拷贝,same-token已颁发。", template.url());
}
}