💡 一、为什么要用 Feign 拦截器?
在微服务架构中,一个请求往往会从「网关 → 服务 A → 服务 B → 服务 C」层层传递。
这时通常会涉及两个关键问题:
- 认证 Token(JWT)如何跨服务自动传递?
- TraceId、RequestId 等链路追踪信息如何在调用链中保留?
如果你不用 Feign 拦截器,就得在每个接口调用处手动添加:
feignClient.getUser(token, id);
这不仅麻烦,还容易出错。
✅ Feign 拦截器(RequestInterceptor) 可以让你一次配置,全局生效。
所有 Feign 请求都会自动带上所需 Header。
⚙️ 二、基础环境
依旧延续上篇的两个服务结构:
| 服务名称 | 功能 | 端口 |
|---|---|---|
| user-service | 被调用方,验证 Token | 8081 |
| order-service | 调用方,自动注入 Token | 8082 |
🧩 三、拦截器机制原理
Feign 提供了接口:
public interface RequestInterceptor {
void apply(RequestTemplate template);
}
Spring Cloud 会自动扫描所有实现该接口的 Bean,在发出 Feign 请求前调用。
简单来说:
调用 Feign → 拦截器自动注入 Header → 发出 HTTP 请求
🧱 四、示例一:自动传递 Token(JWT)
🔧 1️⃣ 创建拦截器类
在 order-service 中新建:
FeignAuthInterceptor.java
@Component
public class FeignAuthInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate template) {
// 模拟从上下文中获取 token(实际可从 ThreadLocal 或 SecurityContext 中取)
String token = UserContextHolder.getToken();
if (StringUtils.hasText(token)) {
template.header("Authorization", "Bearer " + token);
}
// 添加全局 TraceId(例如 Sleuth 生成)
String traceId = MDC.get("traceId");
if (traceId != null) {
template.header("X-Trace-Id", traceId);
}
}
}
🔧 2️⃣ 模拟上下文存储 Token
在 order-service 中添加一个简单的上下文工具类:
UserContextHolder.java
public class UserContextHolder {
private static final ThreadLocal<String> CONTEXT = new ThreadLocal<>();
public static void setToken(String token) {
CONTEXT.set(token);
}
public static String getToken() {
return CONTEXT.get();
}
public static void clear() {
CONTEXT.remove();
}
}
🔧 3️⃣ 控制器中设置 Token
OrderController.java
@RestController
@RequiredArgsConstructor
@RequestMapping("/orders")
public class OrderController {
private final UserClient userClient;
@GetMapping("/{userId}")
public String createOrder(@PathVariable Long userId, @RequestHeader("Authorization") String authHeader) {
// 将用户请求头的 Token 注入上下文
UserContextHolder.setToken(authHeader);
UserDTO user = userClient.getUserById(userId);
UserContextHolder.clear();
return "订单已创建,用户:" + user.getName();
}
}
🧰 4️⃣ 被调用方验证 Token
user-service → UserController.java
@GetMapping("/{id}")
public UserDTO getUserById(@PathVariable Long id, @RequestHeader("Authorization") String token) {
if (!"Bearer test-token".equals(token)) {
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "无效的Token");
}
return new UserDTO(id, "张三-" + id);
}
🧪 5️⃣ 测试效果
请求:
curl -H "Authorization: Bearer test-token" http://localhost:8082/orders/1
返回:
订单已创建,用户:张三-1
如果不传 Token:
{
"status": 401,
"error": "Unauthorized",
"message": "无效的Token"
}
✅ 实现了 Token 自动透传 + 校验机制。
🧩 五、示例二:自动添加 TraceId(链路追踪)
在分布式链路中(例如 Zipkin / Sleuth),TraceId 用于标识一个完整请求路径。
如果你想手动实现简化版 TraceId 传递,只需在拦截器中添加:
String traceId = MDC.get("traceId");
if (traceId == null) {
traceId = UUID.randomUUID().toString();
MDC.put("traceId", traceId);
}
template.header("X-Trace-Id", traceId);
并在日志输出格式中打印:
logging:
pattern:
console: "%d{HH:mm:ss.SSS} [%X{traceId}] %-5level %logger{36} - %msg%n"
效果示例:
11:15:03.123 [abc12345] INFO c.e.o.client.UserClient - 调用用户服务成功
即每个请求都带有自己的 TraceId,方便排查跨服务调用问题。
🧠 六、进阶:拦截器的多场景应用
| 场景 | 说明 | 示例 |
|---|---|---|
| 🔐 认证透传 | 自动传递 JWT / OAuth2 Token | Authorization |
| 🧩 链路追踪 | 自动生成 TraceId 并传递 | X-Trace-Id |
| 🌏 多语言 | 自动带上用户语言环境 | Accept-Language |
| 🧱 灰度流量 | 自动标记灰度标识 | X-Env: gray |
| 🧰 日志追踪 | 在 MDC 中注入 Feign 目标信息 | MDC.put("feign.target", template.url()) |
🪄 七、完整调用链示意图
实用小工具
App Store 截图生成器、应用图标生成器 、在线图片压缩、utc timestamp, ctf tool和 Chrome插件-强制开启复制-护眼模式-网页乱码设置编码
乖猫记账,AI智能分类的最佳聊天记账App。
Elasticsearch可视化客户端工具
2048

被折叠的 条评论
为什么被折叠?



