源码分析-SpringCloudGateway源码阅读-过滤器-路由过滤器源码解读

源码解析-SpringCloudGateway
01 源码分析-SpringCloudGateway源码阅读准备
02 源码分析-SpringCloudGateway源码阅读-网关监控端点
03 源码分析-SpringCloudGateway源码阅读-网关配置类
04 源码分析-SpringCloudGateway源码阅读-服务发现
05 源码分析-SpringCloudGateway源码阅读-网关自定义事件
06 源码分析-SpringCloudGateway源码阅读-过滤器包类总览
07 源码分析-SpringCloudGateway源码阅读-过滤器-全局过滤器源码(一)
08 源码分析-SpringCloudGateway源码阅读-过滤器-全局过滤器源码(二)
09 源码分析-SpringCloudGateway源码阅读-过滤器-全局过滤器源码(三)
10 源码分析-SpringCloudGateway源码阅读-过滤器-路由过滤器源码解读
11 源码分析-SpringCloudGateway源码阅读-处理器源码

一 抽取部分路由过滤器源码

  • PrefixPathGatewayFilterFactory 请求转发路径增加前缀路由过滤器工厂
  • AddRequestHeaderGatewayFilterFactory 增加请求头路由过滤器工厂
  • AddRequestParameterGatewayFilterFactory 增加请求参数路由过滤器工厂
  • AddResponseHeaderGatewayFilterFactory 增加响应头路由过滤器工厂
  • DedupeResponseHeaderGatewayFilterFactory 删除重复响应头路由过滤器工厂
  • MapRequestHeaderGatewayFilterFactory 映射请求头的值为新请求头的路由工厂过滤器
  • PreserveHostHeaderGatewayFilterFactory 转发下游保留Host请求头的路由过滤器工厂
  • RemoveRequestHeaderGatewayFilterFactory 去掉请求头过滤器工厂
  • RemoveRequestParameterGatewayFilterFactory 去除请求参数过滤器工厂
  • RewritePathGatewayFilterFactory 重写路径的路由过滤器工厂
  • SetPathGatewayFilterFactory 设置路径的路由过滤器工厂

二 源码解析

PrefixPathGatewayFilterFactory

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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/*
* Copyright 2013-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.cloud.gateway.filter.factory;

import java.util.Arrays;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import reactor.core.publisher.Mono;

import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.server.ServerWebExchange;

import static org.springframework.cloud.gateway.support.GatewayToStringStyler.filterToStringCreator;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_ALREADY_PREFIXED_ATTR;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.addOriginalRequestUrl;

/**
* 请求转发路径增加前缀路由过滤器工厂
* @author Spencer Gibb
*/
public class PrefixPathGatewayFilterFactory
extends AbstractGatewayFilterFactory<PrefixPathGatewayFilterFactory.Config> {

/**
* Prefix key.
*/
public static final String PREFIX_KEY = "prefix";

private static final Log log = LogFactory
.getLog(PrefixPathGatewayFilterFactory.class);

public PrefixPathGatewayFilterFactory() {
super(Config.class);
}

@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList(PREFIX_KEY);
}

@Override
public GatewayFilter apply(Config config) {
return new GatewayFilter() {
@Override
public Mono<Void> filter(ServerWebExchange exchange,
GatewayFilterChain chain) {
// 是否已经添加前缀
boolean alreadyPrefixed = exchange
.getAttributeOrDefault(GATEWAY_ALREADY_PREFIXED_ATTR, false);
// 如果已经添加了前缀
if (alreadyPrefixed) {
return chain.filter(exchange);
}
// 设置为已添加前缀
exchange.getAttributes().put(GATEWAY_ALREADY_PREFIXED_ATTR, true);

ServerHttpRequest req = exchange.getRequest();
// 内存缓存原始url
addOriginalRequestUrl(exchange, req.getURI());
// 添加前缀组成新的path
String newPath = config.prefix + req.getURI().getRawPath();

ServerHttpRequest request = req.mutate().path(newPath).build();
// GATEWAY_REQUEST_URL_ATTR 设置为添加前缀后的uri
exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, request.getURI());

if (log.isTraceEnabled()) {
log.trace("Prefixed URI with: " + config.prefix + " -> "
+ request.getURI());
}

return chain.filter(exchange.mutate().request(request).build());
}

@Override
public String toString() {
return filterToStringCreator(PrefixPathGatewayFilterFactory.this)
.append("prefix", config.getPrefix()).toString();
}
};
}

public static class Config {

private String prefix;

public String getPrefix() {
return prefix;
}

public void setPrefix(String prefix) {
this.prefix = prefix;
}

}

}

AddRequestHeaderGatewayFilterFactory

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
/*
* Copyright 2013-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.cloud.gateway.filter.factory;

import reactor.core.publisher.Mono;

import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.server.ServerWebExchange;

import static org.springframework.cloud.gateway.support.GatewayToStringStyler.filterToStringCreator;

/**
* 增加请求头路由过滤器工厂
* @author Spencer Gibb
*/
public class AddRequestHeaderGatewayFilterFactory
extends AbstractNameValueGatewayFilterFactory {

@Override
public GatewayFilter apply(NameValueConfig config) {
return new GatewayFilter() {
@Override
public Mono<Void> filter(ServerWebExchange exchange,
GatewayFilterChain chain) {
// 扩展请求头value值
String value = ServerWebExchangeUtils.expand(exchange, config.getValue());
// 重新设置该请求头
ServerHttpRequest request = exchange.getRequest().mutate()
.header(config.getName(), value).build();

return chain.filter(exchange.mutate().request(request).build());
}

@Override
public String toString() {
return filterToStringCreator(AddRequestHeaderGatewayFilterFactory.this)
.append(config.getName(), config.getValue()).toString();
}
};
}

}

AddRequestParameterGatewayFilterFactory

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
/*
* Copyright 2013-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.cloud.gateway.filter.factory;

import java.net.URI;

import reactor.core.publisher.Mono;

import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.UriComponentsBuilder;

import static org.springframework.cloud.gateway.support.GatewayToStringStyler.filterToStringCreator;

/**
* 增加请求参数路由过滤器工厂
* @author Spencer Gibb
*/
public class AddRequestParameterGatewayFilterFactory
extends AbstractNameValueGatewayFilterFactory {

@Override
public GatewayFilter apply(NameValueConfig config) {
return new GatewayFilter() {
@Override
public Mono<Void> filter(ServerWebExchange exchange,
GatewayFilterChain chain) {
URI uri = exchange.getRequest().getURI();
StringBuilder query = new StringBuilder();
String originalQuery = uri.getRawQuery();

if (StringUtils.hasText(originalQuery)) {
query.append(originalQuery);
if (originalQuery.charAt(originalQuery.length() - 1) != '&') {
query.append('&');
}
}
// 扩展请求参数
String value = ServerWebExchangeUtils.expand(exchange, config.getValue());
// TODO urlencode?
query.append(config.getName());
query.append('=');
query.append(value);

try {
URI newUri = UriComponentsBuilder.fromUri(uri)
.replaceQuery(query.toString()).build(true).toUri();

ServerHttpRequest request = exchange.getRequest().mutate().uri(newUri)
.build();

return chain.filter(exchange.mutate().request(request).build());
}
catch (RuntimeException ex) {
throw new IllegalStateException(
"Invalid URI query: \"" + query.toString() + "\"");
}
}

@Override
public String toString() {
return filterToStringCreator(AddRequestParameterGatewayFilterFactory.this)
.append(config.getName(), config.getValue()).toString();
}
};
}

}

AddResponseHeaderGatewayFilterFactory

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
/*
* Copyright 2013-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.cloud.gateway.filter.factory;

import reactor.core.publisher.Mono;

import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.web.server.ServerWebExchange;

import static org.springframework.cloud.gateway.support.GatewayToStringStyler.filterToStringCreator;

/**
* 增加响应头路由过滤器工厂
* @author Spencer Gibb
*/
public class AddResponseHeaderGatewayFilterFactory
extends AbstractNameValueGatewayFilterFactory {

@Override
public GatewayFilter apply(NameValueConfig config) {
return new GatewayFilter() {
@Override
public Mono<Void> filter(ServerWebExchange exchange,
GatewayFilterChain chain) {
// 扩展value值
String value = ServerWebExchangeUtils.expand(exchange, config.getValue());
// 响应头添加header
exchange.getResponse().getHeaders().add(config.getName(), value);

return chain.filter(exchange);
}

@Override
public String toString() {
return filterToStringCreator(AddResponseHeaderGatewayFilterFactory.this)
.append(config.getName(), config.getValue()).toString();
}
};
}

}

DedupeResponseHeaderGatewayFilterFactory

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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
/*
* Copyright 2013-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.cloud.gateway.filter.factory;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import reactor.core.publisher.Mono;

import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.http.HttpHeaders;
import org.springframework.web.server.ServerWebExchange;

import static org.springframework.cloud.gateway.support.GatewayToStringStyler.filterToStringCreator;

/*
Use case: Both your legacy backend and your API gateway add CORS header values. So, your consumer ends up with
Access-Control-Allow-Credentials: true, true
Access-Control-Allow-Origin: https://musk.mars, https://musk.mars
(The one from the gateway will be the first of the two.) To fix, add
DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin

Configuration parameters:
- name
String representing response header names, space separated. Required.
- strategy
RETAIN_FIRST - Default. Retain the first value only.
RETAIN_LAST - Retain the last value only.
RETAIN_UNIQUE - Retain all unique values in the order of their first encounter.

Example 1
default-filters:
- DedupeResponseHeader=Access-Control-Allow-Credentials

Response header Access-Control-Allow-Credentials: true, false
Modified response header Access-Control-Allow-Credentials: true

Example 2
default-filters:
- DedupeResponseHeader=Access-Control-Allow-Credentials, RETAIN_LAST

Response header Access-Control-Allow-Credentials: true, false
Modified response header Access-Control-Allow-Credentials: false

Example 3
default-filters:
- DedupeResponseHeader=Access-Control-Allow-Credentials, RETAIN_UNIQUE

Response header Access-Control-Allow-Credentials: true, true
Modified response header Access-Control-Allow-Credentials: true
*/

/**
* 删除重复响应头路由过滤器工厂
* @author Vitaliy Pavlyuk
*/
public class DedupeResponseHeaderGatewayFilterFactory extends
AbstractGatewayFilterFactory<DedupeResponseHeaderGatewayFilterFactory.Config> {

private static final String STRATEGY_KEY = "strategy";

public DedupeResponseHeaderGatewayFilterFactory() {
super(Config.class);
}

@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList(NAME_KEY, STRATEGY_KEY);
}

@Override
public GatewayFilter apply(Config config) {
return new GatewayFilter() {
@Override
public Mono<Void> filter(ServerWebExchange exchange,
GatewayFilterChain chain) {
return chain.filter(exchange).then(Mono.fromRunnable(
() -> dedupe(exchange.getResponse().getHeaders(), config)));
}

@Override
public String toString() {
return filterToStringCreator(
DedupeResponseHeaderGatewayFilterFactory.this)
.append(config.getName(), config.getStrategy())
.toString();
}
};
}

/**
* 策略枚举
*/
public enum Strategy {

/**
* Default: Retain the first value only.
*/
RETAIN_FIRST,

/**
* Retain the last value only.
*/
RETAIN_LAST,

/**
* Retain all unique values in the order of their first encounter.
*/
RETAIN_UNIQUE

}

void dedupe(HttpHeaders headers, Config config) {
String names = config.getName();
Strategy strategy = config.getStrategy();
if (headers == null || names == null || strategy == null) {
return;
}
for (String name : names.split(" ")) {
dedupe(headers, name.trim(), strategy);
}
}

/**
* 根据策略去重
* @param headers
* @param name
* @param strategy
*/
private void dedupe(HttpHeaders headers, String name, Strategy strategy) {
List<String> values = headers.get(name);
if (values == null || values.size() <= 1) {
return;
}
switch (strategy) {
case RETAIN_FIRST:
headers.set(name, values.get(0));
break;
case RETAIN_LAST:
headers.set(name, values.get(values.size() - 1));
break;
case RETAIN_UNIQUE:
headers.put(name, values.stream().distinct().collect(Collectors.toList()));
break;
default:
break;
}
}

public static class Config extends AbstractGatewayFilterFactory.NameConfig {

private Strategy strategy = Strategy.RETAIN_FIRST;

public Strategy getStrategy() {
return strategy;
}

public Config setStrategy(Strategy strategy) {
this.strategy = strategy;
return this;
}

}

}

MapRequestHeaderGatewayFilterFactory

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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/*
* Copyright 2013-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.cloud.gateway.filter.factory;

import java.util.Arrays;
import java.util.List;

import reactor.core.publisher.Mono;

import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.core.style.ToStringCreator;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.server.ServerWebExchange;

import static org.springframework.cloud.gateway.support.GatewayToStringStyler.filterToStringCreator;

/**
* 映射请求头的值为新请求头的路由工厂过滤器
* @author Tony Clarke
*/
public class MapRequestHeaderGatewayFilterFactory extends
AbstractGatewayFilterFactory<MapRequestHeaderGatewayFilterFactory.Config> {

/**
* From Header key.
*/
public static final String FROM_HEADER_KEY = "fromHeader";

/**
* To Header key.
*/
public static final String TO_HEADER_KEY = "toHeader";

public MapRequestHeaderGatewayFilterFactory() {
super(Config.class);
}

public List<String> shortcutFieldOrder() {
return Arrays.asList(FROM_HEADER_KEY, TO_HEADER_KEY);
}

@Override
public GatewayFilter apply(MapRequestHeaderGatewayFilterFactory.Config config) {
return new GatewayFilter() {
@Override
public Mono<Void> filter(ServerWebExchange exchange,
GatewayFilterChain chain) {
// 如果来源请求头不存在
if (!exchange.getRequest().getHeaders()
.containsKey(config.getFromHeader())) {
return chain.filter(exchange);
}
// 取出来源请求头
List<String> headerValues = exchange.getRequest().getHeaders()
.get(config.getFromHeader());
// 给目标请求头添加请求头值
ServerHttpRequest request = exchange.getRequest().mutate()
.headers(i -> i.addAll(config.getToHeader(), headerValues))
.build();

return chain.filter(exchange.mutate().request(request).build());
}

@Override
public String toString() {
// @formatter:off
return filterToStringCreator(MapRequestHeaderGatewayFilterFactory.this)
.append(FROM_HEADER_KEY, config.getFromHeader())
.append(TO_HEADER_KEY, config.getToHeader())
.toString();
// @formatter:on
}
};
}

public static class Config {

private String fromHeader;

private String toHeader;

public String getFromHeader() {
return this.fromHeader;
}

public Config setFromHeader(String fromHeader) {
this.fromHeader = fromHeader;
return this;
}

public String getToHeader() {
return this.toHeader;
}

public Config setToHeader(String toHeader) {
this.toHeader = toHeader;
return this;
}

@Override
public String toString() {
// @formatter:off
return new ToStringCreator(this)
.append("fromHeader", fromHeader)
.append("toHeader", toHeader)
.toString();
// @formatter:on
}

}

}

PreserveHostHeaderGatewayFilterFactory

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
/*
* Copyright 2013-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.cloud.gateway.filter.factory;

import reactor.core.publisher.Mono;

import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.web.server.ServerWebExchange;

import static org.springframework.cloud.gateway.support.GatewayToStringStyler.filterToStringCreator;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.PRESERVE_HOST_HEADER_ATTRIBUTE;

/**
* 转发下游保留Host请求头的路由过滤器工厂
* @author Spencer Gibb
*/
public class PreserveHostHeaderGatewayFilterFactory extends AbstractGatewayFilterFactory {

public GatewayFilter apply() {
return apply(o -> {
});
}

public GatewayFilter apply(Object config) {
return new GatewayFilter() {
@Override
public Mono<Void> filter(ServerWebExchange exchange,
GatewayFilterChain chain) {
// 设置 保留host头部的属性 为true
exchange.getAttributes().put(PRESERVE_HOST_HEADER_ATTRIBUTE, true);
return chain.filter(exchange);
}

@Override
public String toString() {
return filterToStringCreator(PreserveHostHeaderGatewayFilterFactory.this)
.toString();
}
};
}

}

RemoveRequestHeaderGatewayFilterFactory

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
/*
* Copyright 2013-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.cloud.gateway.filter.factory;

import java.util.Arrays;
import java.util.List;

import reactor.core.publisher.Mono;

import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.server.ServerWebExchange;

import static org.springframework.cloud.gateway.support.GatewayToStringStyler.filterToStringCreator;

/**
* 删除请求头的路由过滤器工厂
* @author Spencer Gibb
*/
public class RemoveRequestHeaderGatewayFilterFactory
extends AbstractGatewayFilterFactory<AbstractGatewayFilterFactory.NameConfig> {

public RemoveRequestHeaderGatewayFilterFactory() {
super(NameConfig.class);
}

@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList(NAME_KEY);
}

@Override
public GatewayFilter apply(NameConfig config) {
return new GatewayFilter() {
@Override
public Mono<Void> filter(ServerWebExchange exchange,
GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest().mutate()
.headers(httpHeaders -> httpHeaders.remove(config.getName()))
.build();

return chain.filter(exchange.mutate().request(request).build());
}

@Override
public String toString() {
return filterToStringCreator(RemoveRequestHeaderGatewayFilterFactory.this)
.append("name", config.getName()).toString();
}
};
}

}

RemoveRequestParameterGatewayFilterFactory

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
/*
* Copyright 2013-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.cloud.gateway.filter.factory;

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

import reactor.core.publisher.Mono;

import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.UriComponentsBuilder;

import static org.springframework.cloud.gateway.support.GatewayToStringStyler.filterToStringCreator;
import static org.springframework.util.CollectionUtils.unmodifiableMultiValueMap;

/**
* 删除请求参数的路由过滤器工厂
* @author Thirunavukkarasu Ravichandran
*/
public class RemoveRequestParameterGatewayFilterFactory
extends AbstractGatewayFilterFactory<AbstractGatewayFilterFactory.NameConfig> {

public RemoveRequestParameterGatewayFilterFactory() {
super(NameConfig.class);
}

@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList(NAME_KEY);
}

@Override
public GatewayFilter apply(NameConfig config) {
return new GatewayFilter() {
@Override
public Mono<Void> filter(ServerWebExchange exchange,
GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
// 取出查询参数
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>(
request.getQueryParams());
// 去掉查询参数
queryParams.remove(config.getName());

// 替换查询参数
URI newUri = UriComponentsBuilder.fromUri(request.getURI())
.replaceQueryParams(unmodifiableMultiValueMap(queryParams))
.build().toUri();

ServerHttpRequest updatedRequest = exchange.getRequest().mutate()
.uri(newUri).build();

return chain.filter(exchange.mutate().request(updatedRequest).build());
}

@Override
public String toString() {
return filterToStringCreator(
RemoveRequestParameterGatewayFilterFactory.this)
.append("name", config.getName()).toString();
}
};
}

}

RewritePathGatewayFilterFactory

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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/*
* Copyright 2013-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.cloud.gateway.filter.factory;

import java.util.Arrays;
import java.util.List;

import reactor.core.publisher.Mono;

import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.Assert;
import org.springframework.web.server.ServerWebExchange;

import static org.springframework.cloud.gateway.support.GatewayToStringStyler.filterToStringCreator;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.addOriginalRequestUrl;

/**
* 重写路径的路由过滤器工厂
* @author Spencer Gibb
*/
public class RewritePathGatewayFilterFactory
extends AbstractGatewayFilterFactory<RewritePathGatewayFilterFactory.Config> {

/**
* Regexp key.
*/
public static final String REGEXP_KEY = "regexp";

/**
* Replacement key.
*/
public static final String REPLACEMENT_KEY = "replacement";

public RewritePathGatewayFilterFactory() {
super(Config.class);
}

@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList(REGEXP_KEY, REPLACEMENT_KEY);
}

@Override
public GatewayFilter apply(Config config) {
String replacement = config.replacement.replace("$\\", "$");
return new GatewayFilter() {
@Override
public Mono<Void> filter(ServerWebExchange exchange,
GatewayFilterChain chain) {
ServerHttpRequest req = exchange.getRequest();
// 保存原始请求url
addOriginalRequestUrl(exchange, req.getURI());
String path = req.getURI().getRawPath();
// 通过正则替换出新的url路径
String newPath = path.replaceAll(config.regexp, replacement);

ServerHttpRequest request = req.mutate().path(newPath).build();
// 设置 网关请求url属性值 为替换之后的uri
exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, request.getURI());

return chain.filter(exchange.mutate().request(request).build());
}

@Override
public String toString() {
return filterToStringCreator(RewritePathGatewayFilterFactory.this)
.append(config.getRegexp(), replacement).toString();
}
};
}

public static class Config {

private String regexp;

private String replacement;

public String getRegexp() {
return regexp;
}

public Config setRegexp(String regexp) {
Assert.hasText(regexp, "regexp must have a value");
this.regexp = regexp;
return this;
}

public String getReplacement() {
return replacement;
}

public Config setReplacement(String replacement) {
Assert.notNull(replacement, "replacement must not be null");
this.replacement = replacement;
return this;
}

}

}

SetPathGatewayFilterFactory

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
97
98
99
100
101
102
103
/*
* Copyright 2013-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.cloud.gateway.filter.factory;

import java.net.URI;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import reactor.core.publisher.Mono;

import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.UriTemplate;

import static org.springframework.cloud.gateway.support.GatewayToStringStyler.filterToStringCreator;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.addOriginalRequestUrl;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.getUriTemplateVariables;

/**
* 设置路径的路由过滤器工厂
* @author Spencer Gibb
*/
public class SetPathGatewayFilterFactory
extends AbstractGatewayFilterFactory<SetPathGatewayFilterFactory.Config> {

/**
* Template key.
*/
public static final String TEMPLATE_KEY = "template";

public SetPathGatewayFilterFactory() {
super(Config.class);
}

@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList(TEMPLATE_KEY);
}

@Override
public GatewayFilter apply(Config config) {
UriTemplate uriTemplate = new UriTemplate(config.template);

return new GatewayFilter() {
@Override
public Mono<Void> filter(ServerWebExchange exchange,
GatewayFilterChain chain) {
ServerHttpRequest req = exchange.getRequest();
addOriginalRequestUrl(exchange, req.getURI());
// 获取uri模板参数和值
Map<String, String> uriVariables = getUriTemplateVariables(exchange);
// 通过uri模板直接替换出新的uri
URI uri = uriTemplate.expand(uriVariables);
String newPath = uri.getRawPath();

exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, uri);

ServerHttpRequest request = req.mutate().path(newPath).build();

return chain.filter(exchange.mutate().request(request).build());
}

@Override
public String toString() {
return filterToStringCreator(SetPathGatewayFilterFactory.this)
.append("template", config.getTemplate()).toString();
}
};
}

public static class Config {

private String template;

public String getTemplate() {
return template;
}

public void setTemplate(String template) {
this.template = template;
}

}

}