SpringCloudGateway手动编写路由规则对请求进行转发

algorain

这篇文章主要是提供一种转发路由的代码实现方式,之前说的gateway都是使用配置文件来对请求进行路由,这样虽然很简单,但是不够灵活,如果后端对应很多服务实例,网关想要根据自己的规则来转发请求,比如编写不同的负载均衡策略,做一些特别的权重,以及在运行过程中动态的变更转发地址,这些用配置文件来做都不够灵活,没法自由的定义规则。 涉及的gateway版本

1
2
3
4
5
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<version>2.1.4.RELEASE</version>
</dependency>

主要实现过程还是实现GatewayFilter接口,获取到要指定的IP地址与端口,然后组装成URI与Route,最后转发出去

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
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.ecwid.consul.v1.health.model.HealthService;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.UriComponentsBuilder;

import java.net.URI;
import java.util.List;
import java.util.Optional;

import reactor.core.publisher.Mono;

import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR;

/**
* 转发路由,通过负载均衡对后端服务进行访问
*
*/
@Slf4j
public class RouteFilter implements GatewayFilter, Ordered {

@Autowired
private RedisUtil redisUtil;

@Autowired
private LoadBalanceHandler loadBalance;

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpResponse response = exchange.getResponse();
//获取原来的请求路径
String requestPath = exchange.getAttribute(FilterDict.SYSTEM_REQUEST_PATH);
//randomSelectInstance方法会获取到一个"ip:port"这样结构的字符串
String instanceInfo = loadBalance.randomSelectInstance();
//如果没有服务,则直接返回报错
if (StrUtil.isEmpty(instanceInfo)) {
return response.writeWith(Mono.just(GateWayFilterUtils.writeData(exchange, RecoError.GEN_SERVER_BUSY)));
}
//用于测试负载均衡算法对IP分配是否均衡
// redisUtil.zIncrementScore("test:gateway:load:ip",instanceInfo,1);
//分割地址中IP和端口
String[] serviceAddress = instanceInfo.split(StrUtil.COLON);
String requestSchema = exchange.getRequest().getURI().getScheme();
//拼接URL的数据
assert ObjectUtil.isNotNull(requestPath);
URI uri = UriComponentsBuilder.
newInstance().scheme(requestSchema).
host(serviceAddress[0].trim()).port(Integer.parseInt(serviceAddress[1].trim()))
.path(requestPath).query(exchange.getRequest().getURI().getRawQuery()).build(true)
.toUri();
//将拼接好的URL装入新的exchange
ServerWebExchange mutateExchange = exchange.mutate().request(builder -> builder.uri(uri).build()).build();
Optional<Route> route = Optional.of(exchange.getAttribute(GATEWAY_ROUTE_ATTR));
Route newRoute = Route.async()
.asyncPredicate(route.get().getPredicate())
.filters(route.get().getFilters())
.id(route.get().getId())
.order(route.get().getOrder())
.uri(uri).build();
mutateExchange.getAttributes().put(GATEWAY_ROUTE_ATTR, newRoute);
mutateExchange.getAttributes().put(FilterDict.SYSTEM_APP_IP_ADDR, serviceAddress[0]);
return chain.filter(mutateExchange);
}

@Override
public int getOrder() {
return FilterDict.SYSTEM_FILTER_ORDER + 4;
}
}

单独编写路由filter以后,还需要引入才能执行,在全局配置中倒入bean,最后启动就可以执行了

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
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.ratelimit.RedisRateLimiter;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import lombok.extern.slf4j.Slf4j;

import java.time.Duration;

/**
* 全局过滤器配置加载
*
* @author :wcy
*/
@Slf4j
@Configuration
public class GlobalFilterConfigure {
//用于设置路由的
@Bean
public RouteFilter routeFilter(){
return new RouteFilter();
}

/**
* 将所有自定义的filter加载进来
*/
@Bean
public RouteLocator customerRouteLocator(RouteLocatorBuilder builder, RedisRateLimiter redisRateLimiter) {
return builder.routes()
.route(r -> r.path(FilterDict.GATEWAY_BASE_INTERCEPT_URL)
//将自定义的filter加载进来
.filters(f -> f.filters(routeFilter())
//请求大小
.setRequestSize(requestLimitSize)
//请求限流,目前使用请求IP,以后可以扩展使用其他限定组合
// .filter(rateLimitByIpGatewayFilter())
)
.uri("http://127.0.0.1:" + servicePort + "/actuator/health")
.order(FilterDict.SYSTEM_FILTER_ORDER)
.id(FilterDict.GATEWAY_ROUTE_NAME)
).build();
}

}

  • Title: SpringCloudGateway手动编写路由规则对请求进行转发
  • Author: algorain
  • Created at: 2021-06-25 19:09:07
  • Updated at: 2023-05-14 21:39:50
  • Link: http://www.rain1024.com/2021/06/25/springcloudgateway手动编写路由规则对请求进行转发/
  • License: This work is licensed under CC BY-NC-SA 4.0.
 Comments
On this page
SpringCloudGateway手动编写路由规则对请求进行转发