Skip to content

Commit c072dab

Browse files
committed
feat: 定义 feign client 装饰器,实现请求与响应的拦截处理
1 parent 7d41866 commit c072dab

3 files changed

Lines changed: 139 additions & 41 deletions

File tree

Lines changed: 27 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,17 @@
11
package com.github.cadecode.uniboot.framework.api.config;
22

3-
import cn.hutool.core.util.CharsetUtil;
4-
import cn.hutool.core.util.EscapeUtil;
5-
import cn.hutool.core.util.ObjectUtil;
6-
import cn.hutool.core.util.StrUtil;
7-
import cn.hutool.extra.servlet.ServletUtil;
8-
import com.github.cadecode.uniboot.common.core.util.JacksonUtil;
9-
import com.github.cadecode.uniboot.framework.api.bean.dto.SysUserDto.SysUserDetailsDto;
10-
import com.github.cadecode.uniboot.framework.api.consts.SecurityConst;
11-
import com.github.cadecode.uniboot.framework.api.util.SecurityUtil;
12-
import feign.RequestInterceptor;
3+
import com.github.cadecode.uniboot.framework.api.feign.FeignClientDecorator;
4+
import feign.Client;
5+
import feign.Client.Default;
6+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
7+
import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryFactory;
8+
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
9+
import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties;
10+
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
11+
import org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient;
12+
import org.springframework.cloud.openfeign.loadbalancer.RetryableFeignBlockingLoadBalancerClient;
1313
import org.springframework.context.annotation.Bean;
1414
import org.springframework.context.annotation.Configuration;
15-
import org.springframework.web.context.request.RequestContextHolder;
16-
import org.springframework.web.context.request.ServletRequestAttributes;
17-
18-
import javax.servlet.http.HttpServletRequest;
1915

2016
/**
2117
* OpenFeign 配置类
@@ -26,33 +22,23 @@
2622
@Configuration
2723
public class FeignConfig {
2824

25+
// 覆盖 feign 配置
26+
// org.springframework.cloud.openfeign.loadbalancer.DefaultFeignLoadBalancerConfiguration
27+
28+
@Bean
29+
@ConditionalOnProperty(value = "spring.cloud.loadbalancer.retry.enabled", havingValue = "false")
30+
public Client feignClient(LoadBalancerClient loadBalancerClient, LoadBalancerProperties properties,
31+
LoadBalancerClientFactory loadBalancerClientFactory) {
32+
FeignClientDecorator decorator = new FeignClientDecorator(new Default(null, null));
33+
return new FeignBlockingLoadBalancerClient(decorator, loadBalancerClient, properties, loadBalancerClientFactory);
34+
}
35+
2936
@Bean
30-
public RequestInterceptor requestInterceptor() {
31-
return requestTemplate -> {
32-
// 获取请求对象
33-
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
34-
// 非请求接口内的调用
35-
if (ObjectUtil.isNull(requestAttributes)) {
36-
return;
37-
}
38-
HttpServletRequest sRequest = requestAttributes.getRequest();
39-
if (ObjectUtil.isNull(sRequest)) {
40-
return;
41-
}
42-
// 传递用户 token
43-
String token = SecurityUtil.getTokenFromRequest(sRequest);
44-
if (StrUtil.isNotEmpty(token)) {
45-
requestTemplate.header(SecurityConst.HEAD_TOKEN, token);
46-
}
47-
// 传递用户详细信息
48-
String userDetailsJson = ServletUtil.getHeader(sRequest, SecurityConst.HEAD_USER_DETAILS, CharsetUtil.CHARSET_UTF_8);
49-
if (StrUtil.isEmpty(userDetailsJson)) {
50-
SysUserDetailsDto userDetailsDto = SecurityUtil.getUserDetails(null);
51-
userDetailsJson = JacksonUtil.toJson(userDetailsDto);
52-
}
53-
requestTemplate.header(SecurityConst.HEAD_USER_DETAILS, EscapeUtil.escape(userDetailsJson));
54-
// 配置客户端 IP
55-
requestTemplate.header("X-Forwarded-For", ServletUtil.getClientIP(sRequest));
56-
};
37+
@ConditionalOnProperty(value = "spring.cloud.loadbalancer.retry.enabled", havingValue = "true", matchIfMissing = true)
38+
public Client feignRetryClient(LoadBalancerClient loadBalancerClient, LoadBalancedRetryFactory loadBalancedRetryFactory,
39+
LoadBalancerProperties properties, LoadBalancerClientFactory loadBalancerClientFactory) {
40+
FeignClientDecorator decorator = new FeignClientDecorator(new Default(null, null));
41+
return new RetryableFeignBlockingLoadBalancerClient(decorator, loadBalancerClient, loadBalancedRetryFactory, properties, loadBalancerClientFactory);
5742
}
43+
5844
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package com.github.cadecode.uniboot.framework.api.feign;
2+
3+
import cn.hutool.core.util.CharsetUtil;
4+
import cn.hutool.core.util.EscapeUtil;
5+
import cn.hutool.core.util.ObjectUtil;
6+
import cn.hutool.core.util.StrUtil;
7+
import cn.hutool.extra.servlet.ServletUtil;
8+
import com.github.cadecode.uniboot.common.core.util.JacksonUtil;
9+
import com.github.cadecode.uniboot.framework.api.bean.dto.SysUserDto.SysUserDetailsDto;
10+
import com.github.cadecode.uniboot.framework.api.consts.SecurityConst;
11+
import com.github.cadecode.uniboot.framework.api.util.RequestUtil;
12+
import com.github.cadecode.uniboot.framework.api.util.SecurityUtil;
13+
import feign.Client;
14+
import feign.Request;
15+
import feign.Request.Options;
16+
import feign.RequestTemplate;
17+
import feign.Response;
18+
19+
import javax.servlet.http.HttpServletRequest;
20+
import javax.servlet.http.HttpServletResponse;
21+
import java.io.IOException;
22+
import java.util.Collection;
23+
import java.util.Map;
24+
25+
/**
26+
* FeignClient 装饰器
27+
*
28+
* @author Cade Li
29+
* @since 2023/8/1
30+
*/
31+
public class FeignClientDecorator implements Client {
32+
33+
private final Client delegate;
34+
35+
public FeignClientDecorator(Client delegate) {
36+
this.delegate = delegate;
37+
}
38+
39+
@Override
40+
public Response execute(Request request, Options options) throws IOException {
41+
configRequestTemplate(request.requestTemplate());
42+
Response response = delegate.execute(request, options);
43+
getResponseHeader(response.headers());
44+
return response;
45+
}
46+
47+
protected void configRequestTemplate(RequestTemplate requestTemplate) {
48+
HttpServletRequest servletRequest = RequestUtil.getRequest();
49+
if (ObjectUtil.isNull(servletRequest)) {
50+
return;
51+
}
52+
// 传递用户 token
53+
String token = SecurityUtil.getTokenFromRequest(servletRequest);
54+
if (StrUtil.isNotEmpty(token)) {
55+
requestTemplate.header(SecurityConst.HEAD_TOKEN, token);
56+
}
57+
// 传递用户详细信息
58+
String userDetailsJson = ServletUtil.getHeader(servletRequest, SecurityConst.HEAD_USER_DETAILS, CharsetUtil.CHARSET_UTF_8);
59+
if (StrUtil.isEmpty(userDetailsJson)) {
60+
SysUserDetailsDto userDetailsDto = SecurityUtil.getUserDetails(null);
61+
userDetailsJson = JacksonUtil.toJson(userDetailsDto);
62+
}
63+
requestTemplate.header(SecurityConst.HEAD_USER_DETAILS, EscapeUtil.escape(userDetailsJson));
64+
// 配置客户端 IP
65+
requestTemplate.header("X-Forwarded-For", ServletUtil.getClientIP(servletRequest));
66+
}
67+
68+
protected void getResponseHeader(Map<String, Collection<String>> headers) {
69+
HttpServletResponse servletResponse = RequestUtil.getResponse();
70+
if (ObjectUtil.isNull(servletResponse)) {
71+
return;
72+
}
73+
// 获取 token
74+
if (headers.containsKey(SecurityConst.HEAD_TOKEN)) {
75+
String token = headers.get(SecurityConst.HEAD_TOKEN).stream().findFirst().get();
76+
servletResponse.addHeader(SecurityConst.HEAD_TOKEN, token);
77+
}
78+
}
79+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.github.cadecode.uniboot.framework.api.util;
2+
3+
import cn.hutool.core.util.ObjectUtil;
4+
import org.springframework.web.context.request.RequestContextHolder;
5+
import org.springframework.web.context.request.ServletRequestAttributes;
6+
7+
import javax.servlet.http.HttpServletRequest;
8+
import javax.servlet.http.HttpServletResponse;
9+
10+
/**
11+
* spring web 工具类
12+
*
13+
* @author Cade Li
14+
* @since 2023/8/1
15+
*/
16+
public class RequestUtil {
17+
18+
public static HttpServletRequest getRequest() {
19+
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
20+
if (ObjectUtil.isNull(requestAttributes)) {
21+
return null;
22+
}
23+
return requestAttributes.getRequest();
24+
}
25+
26+
public static HttpServletResponse getResponse() {
27+
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
28+
if (ObjectUtil.isNull(requestAttributes)) {
29+
return null;
30+
}
31+
return requestAttributes.getResponse();
32+
}
33+
}

0 commit comments

Comments
 (0)