Gateway网关搭建
Damoncai 9/26/2022 wogua
# 网关搭建
使用Spring Cloud Gateway构建一个全新的微服务网关
- 基于Reactor模型的WebFlux构建,运行在Netty上,具有更好的性能;
- 可拓展性高,内置了非常丰富的转发规则,除此之外,我们也可以定义自己的转发规则。
# 基础网关搭建
详细请移步至http://www.helloworld.center/docs/mashibing/03.springcloud2022/04.gateway.html
目前只搭建了wogua-auth
所以这里的转发规则为:
server:
port: 8301
spring:
application:
name: WoGua-Gateway
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
gateway:
routes:
- id: WoGua-Auth
uri: lb://WoGua-Auth
predicates:
- Path=/auth/**
filters:
- StripPrefix=1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 过滤器扩展
# 请求Filter
请求过滤器主要作用是在网关层面上面给请求的请求头添加额外信息,然后在各个具体服务中提取相关信息,用来实现请求不能直接访问各个具体服务,需要由网关转发
/**
* WoguaGatewayRequestFilter: 将请求头添加额外请求头,用于各个服务查看证明从网关转发到服务,并不是直接访问的服务
*/
@Component
public class WoguaGatewayRequestFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
byte[] token = Base64Utils.encode(("wogua-gateway-value").getBytes());
ServerHttpRequest build = request.mutate().header("wogua-gateway-key", new String(token)).build();
ServerWebExchange newExchange = exchange.mutate().request(build).build();
return chain.filter(newExchange);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 日志转发过滤器
用来转发各个请求
@Slf4j
@Component
public class WoguaGatewayLogtFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
URI url = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR);
Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
LinkedHashSet<URI> uris = exchange.getAttribute(GATEWAY_ORIGINAL_REQUEST_URL_ATTR);
URI originUri = null;
if (uris != null) {
originUri = uris.stream().findFirst().orElse(null);
}
if (url != null && route != null && originUri != null) {
log.info("转发请求:{}://{}{} --> 目标服务:{},目标地址:{}://{}{},转发时间:{}",
originUri.getScheme(), originUri.getAuthority(), originUri.getPath(),
route.getId(), url.getScheme(), url.getAuthority(), url.getPath(), LocalDateTime.now()
);
}
return chain.filter(exchange);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 网关异常处理
创建handler包
创建WoguaGatewayExceptionHandler
类
@Slf4j
public class WoguaGatewayExceptionHandler extends DefaultErrorWebExceptionHandler {
public WoguaGatewayExceptionHandler(ErrorAttributes errorAttributes, ResourceProperties resourceProperties,
ErrorProperties errorProperties, ApplicationContext applicationContext) {
super(errorAttributes, resourceProperties, errorProperties, applicationContext);
}
/**
* 异常处理,定义返回报文格式
*/
@Override
protected Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace) {
Throwable error = super.getError(request);
log.error(
"请求发生异常,请求URI:{},请求方法:{},异常信息:{}",
request.path(), request.methodName(), error.getMessage()
);
String errorMessage;
if (error instanceof NotFoundException) {
String serverId = StringUtils.substringAfterLast(error.getMessage(), "Unable to find instance for ");
serverId = StringUtils.replace(serverId, "\"", StringUtils.EMPTY);
errorMessage = String.format("无法找到%s服务", serverId);
} else if (StringUtils.containsIgnoreCase(error.getMessage(), "connection refused")) {
errorMessage = "目标服务拒绝连接";
} else if (error instanceof TimeoutException) {
errorMessage = "访问服务超时";
} else if (error instanceof ResponseStatusException
&& StringUtils.containsIgnoreCase(error.getMessage(), HttpStatus.NOT_FOUND.toString())) {
errorMessage = "未找到该资源";
} else {
errorMessage = "网关转发异常";
}
Map<String, Object> errorAttributes = new HashMap<>(3);
errorAttributes.put("message", errorMessage);
return errorAttributes;
}
@Override
@SuppressWarnings("all")
protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
}
@Override
protected int getHttpStatus(Map<String, Object> errorAttributes) {
return HttpStatus.INTERNAL_SERVER_ERROR.value();
}
}
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
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
创建configure包
创建WoguaGatewayErrorConfigure类
@Configuration
public class WoguaGatewayErrorConfigure {
private final ServerProperties serverProperties;
private final ApplicationContext applicationContext;
private final ResourceProperties resourceProperties;
private final List<ViewResolver> viewResolvers;
private final ServerCodecConfigurer serverCodecConfigurer;
public WoguaGatewayErrorConfigure(ServerProperties serverProperties,
ResourceProperties resourceProperties,
ObjectProvider<List<ViewResolver>> viewResolversProvider,
ServerCodecConfigurer serverCodecConfigurer,
ApplicationContext applicationContext) {
this.serverProperties = serverProperties;
this.applicationContext = applicationContext;
this.resourceProperties = resourceProperties;
this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
this.serverCodecConfigurer = serverCodecConfigurer;
}
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public ErrorWebExceptionHandler errorWebExceptionHandler(ErrorAttributes errorAttributes) {
WoguaGatewayExceptionHandler exceptionHandler = new WoguaGatewayExceptionHandler(
errorAttributes,
this.resourceProperties,
this.serverProperties.getError(),
this.applicationContext);
exceptionHandler.setViewResolvers(this.viewResolvers);
exceptionHandler.setMessageWriters(this.serverCodecConfigurer.getWriters());
exceptionHandler.setMessageReaders(this.serverCodecConfigurer.getReaders());
return exceptionHandler;
}
}
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
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
关闭wogua-auth服务,再发起请求