feign 源码解析 && RequestInterceptor

参考:Feign源码解析

2021-12-24 16:27:48

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package com.amoros.pumpkin.scorecard.infrastructure.config;

import com.amoros.cloud.core.AgentId;
import com.amoros.pumpkin.scorecard.common.constants.BizConstants;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

/**
* feign 请求拦截器。可以添加 headers
* 2021-12-09 16:36:05
*/
@Component
@Slf4j
public class FeignRequestInterceptor implements RequestInterceptor {

@Override
public void apply(RequestTemplate requestTemplate) {
String agentUid = AgentId.getAgentUid();
if (StringUtils.isNotEmpty(agentUid)) {
log.info("FeignRequestInterceptor feign拦截器,请求 AgentId = " + agentUid);
requestTemplate.header(BizConstants.X_CHANGE_DATA_SOURCE, agentUid);
return;
}

log.warn("FeignRequestInterceptor feign拦截器,请求 AgentId 未设置");
}
}

2022-08-15 11:03:46

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package com.amoros.hawkeye.config;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.amoros.hawkeye.context.TenantIdHolder;
import com.amoros.hawkeye.context.UserIdHolder;
import com.amoros.hawkeye.util.MDCUtil;
import lombok.extern.slf4j.Slf4j;
import top.legendscloud.common.base.ComResp;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
* Hawkeye 拦截器
*/
@Slf4j
@WebFilter(filterName = "com.amoros.hawkeye.config.HawkeyeFilter", urlPatterns = {
"/bi/*",
"/actionConfig/*",
"/actionRelDetailConfig/*",
"/ruleConfig/*",
"/scheduleConfig/*",
"/tenantConfig/*"
})
public class HawkeyeFilter implements Filter {

/**
* 租户ID
*/
public static final String TENANT_ID = "X-Change-Data-Source";

/**
* 用户ID
*/
public static final String USER_ID = "X-User-Id";

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;

MDCUtil.set(req);
log.info("=========================================== HawkeyeFilter 拦截了...");

String tenantId = req.getHeader(TENANT_ID);

// 所有请求租户ID必须有
if (StrUtil.isBlank(tenantId)) {
String errorMessage = StrUtil.format("请设置 header '{}'", TENANT_ID);
log.error(errorMessage);

ComResp comResp = new ComResp.Builder().fail().msg(errorMessage).build();

resp.setContentType("application/json;charset=utf8");
resp.getWriter().write(JSONUtil.toJsonStr(comResp));
return;
}
TenantIdHolder.set(tenantId);
UserIdHolder.set(req.getHeader(USER_ID));

// 执行下一个拦截器
chain.doFilter(request, response);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96

package com.amoros.hawkeye.config;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.amoros.hawkeye.context.JobContext;
import com.amoros.hawkeye.context.TenantIdHolder;
import com.amoros.hawkeye.context.UserIdHolder;
import com.amoros.hawkeye.exception.HawkeyeException;
import com.amoros.hawkeye.util.MDCUtil;
import datart.api.config.DatartProperties;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import lombok.extern.slf4j.Slf4j;
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;

/**
* <pre>
* web -> me -> feign
* 把别人调用我的 header 放入 我调用别人的 feign 请求中
* </pre>
*/
@Slf4j
@Component
public class HawkeyeFeignRequestInterceptor implements RequestInterceptor {

/**
* 租户ID
*/
public static final String TENANT_ID = "X-Change-Data-Source";

/**
* 用户ID
*/
public static final String USER_ID = "X-User-Id";

@Override
public void apply(RequestTemplate template) {
// datart 服务,直接跳过
String serviceName = template.feignTarget().name();
if (DatartProperties.SERVICE_NAME.equals(serviceName)) {
return;
}


try {
// 0、traceId
MDCUtil.set(template);

// 1、mvc.header => feign.header
// headerCopy(template);

// 2、Holder.get => headers.put
String tenantId = TenantIdHolder.get();
if (StrUtil.isNotBlank(tenantId)) {
log.info("feign 拦截:TenantIdHolder 设置租户id=[{}]", tenantId);
template.removeHeader(TENANT_ID);
template.header(TENANT_ID, tenantId);
template.header(USER_ID, UserIdHolder.get());
return;
}

// 3、TENANT_ID 未设置 => throw
Assert.notEmpty(template.headers().get(TENANT_ID), "请设置租户id");
} catch (Exception e) {
throw new HawkeyeException("设置feign请求头信息异常", e);
}
}

/**
* 当前上下文中的请求header 放入 feign请求header
*/
private void headerCopy(RequestTemplate template) {
// 1、Job => return
if (JobContext.getJobExecutionContext() != null) {
return;
}

// 2、Controller => mvc.headers => feign.headers
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
Enumeration headerNames = request.getHeaderNames();
if (headerNames != null) {
while (headerNames.hasMoreElements()) {
String name = (String) headerNames.nextElement();
String values = request.getHeader(name);
template.header(name, values);
}
}
}
}