Spring 云网关自定义路由
Spring Cloud Gateway custom route
我正在尝试使用 spring 云网关为以下场景定义路由:
http://gateway-url/service-url?token=foo_bar => 被转发到服务 url.
http://gateway-url/service-url => 被转发到其他地方
这是我目前得到的。
@Bean
public RouteLocator customRouteLocator( RouteLocatorBuilder builder,
RouteServiceForwardingFilter forwardingFilter) {
return builder.routes()
.route(r ->
r.query("token")
.filters(f -> {
f.filter(forwardingFilter, ROUTE_TO_URL_FILTER_ORDER + 1);
return f;
})
.uri("http://google.com:80")
.id("token_route"))
.build();
}
这是我创建的过滤器
@Component
public class RouteServiceForwardingFilter implements GatewayFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
try {
String forwardUrl = exchange.getRequest().getURI().toString();
forwardUrl = forwardUrl.substring(0, forwardUrl.lastIndexOf("?"));
exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, new URI(forwardUrl));
return chain.filter(exchange);
} catch (URISyntaxException e) {
exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
return Mono.empty();
}
}
}
所以在这里和那里看了一会儿之后,我想到了这个实现,它完全符合我的要求。
我这样编辑问题中描述的过滤器:
/**
* Checks whether the user is using a valid token or not.
* If the token is a valid one, a header named AUTHENTICATED is added
* to the request and the user is forwarded to the same url with the new request.
* If not, we forward to the same url but removing the token from it.
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String forwardUrl = exchange.getRequest().getURI().toString();
String queryParam = exchange.getRequest().getQueryParams().getFirst(Constants.TOKEN);
try {
// 1 means he is connected
if (queryParam.equals("1")) {
ServerHttpRequest request = exchange.getRequest().mutate().
header(Constants.AUTHENTICATED, "true").
build();
return chain.filter(exchange.mutate().request(request).build());
}
if (forwardUrl.contains("?")) {
forwardUrl = removeQueryParam(forwardUrl, Constants.TOKEN);
}
exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, new URI(forwardUrl));
return chain.filter(exchange);
} catch (URISyntaxException e) {
return Mono.empty();
}
}
/**
* Removes a query param and its value from a given url
* @param url the url to be modified.
* @param queryParam the parameter to be removed.
* @return the url wihtout the query param to be removed
* or the same url in case that query param isn't in that given url
*/
public static String removeQueryParam( String url, String queryParam ) {
String result = "";
String[] urlParts = url.split("\?");
if (urlParts.length >= 2) {
String[] urlParams = urlParts[urlParts.length - 1].split("&");
for (String urlParam : urlParams) {
String[] param = urlParam.split("=");
if (!param[0].equals(queryParam)) {
result += urlParam + "&";
}
}
result = urlParts[0] + (result.length() > 0 ? "?" + result.substring(0, result.length() - 1) : "");
} else {
result = url;
}
return result;
}
然后我添加了这两条路由:
/**
* Adds custom routes to the application
*/
@Bean
public RouteLocator customRouteLocator( RouteLocatorBuilder builder,
SimpleLoggingFilter loggingFilter,
RouteServiceForwardingFilter forwardingFilter) {
return builder.routes()
.route(r ->
r.query(Constants.TOKEN).negate()
.filters(f -> {
f.filter(loggingFilter);
try {
f.redirect(HttpStatus.UNAUTHORIZED, new URL("http://www.example.com/401"));
} catch (MalformedURLException e) {
LOGGER.error(e.getMessage());
}
return f;
})
.uri("http://www.example.com/401")
.id("WITHOUT_token"))
.route(r ->
r.query(Constants.TOKEN)
.and()
.header(Constants.AUTHENTICATED).negate()
.filters(f -> {
f.filter(loggingFilter);
f.filter(forwardingFilter, Constants.ROUTE_TO_URL_FILTER_ORDER + 1);
return f;
})
.uri("http://localhost:8008")
.id("with_token"))
.build();
}
然后就解决了。我希望这对其他人有帮助。
我正在尝试使用 spring 云网关为以下场景定义路由:
http://gateway-url/service-url?token=foo_bar => 被转发到服务 url.
http://gateway-url/service-url => 被转发到其他地方
这是我目前得到的。
@Bean
public RouteLocator customRouteLocator( RouteLocatorBuilder builder,
RouteServiceForwardingFilter forwardingFilter) {
return builder.routes()
.route(r ->
r.query("token")
.filters(f -> {
f.filter(forwardingFilter, ROUTE_TO_URL_FILTER_ORDER + 1);
return f;
})
.uri("http://google.com:80")
.id("token_route"))
.build();
}
这是我创建的过滤器
@Component
public class RouteServiceForwardingFilter implements GatewayFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
try {
String forwardUrl = exchange.getRequest().getURI().toString();
forwardUrl = forwardUrl.substring(0, forwardUrl.lastIndexOf("?"));
exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, new URI(forwardUrl));
return chain.filter(exchange);
} catch (URISyntaxException e) {
exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
return Mono.empty();
}
}
}
所以在这里和那里看了一会儿之后,我想到了这个实现,它完全符合我的要求。
我这样编辑问题中描述的过滤器:
/**
* Checks whether the user is using a valid token or not.
* If the token is a valid one, a header named AUTHENTICATED is added
* to the request and the user is forwarded to the same url with the new request.
* If not, we forward to the same url but removing the token from it.
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String forwardUrl = exchange.getRequest().getURI().toString();
String queryParam = exchange.getRequest().getQueryParams().getFirst(Constants.TOKEN);
try {
// 1 means he is connected
if (queryParam.equals("1")) {
ServerHttpRequest request = exchange.getRequest().mutate().
header(Constants.AUTHENTICATED, "true").
build();
return chain.filter(exchange.mutate().request(request).build());
}
if (forwardUrl.contains("?")) {
forwardUrl = removeQueryParam(forwardUrl, Constants.TOKEN);
}
exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, new URI(forwardUrl));
return chain.filter(exchange);
} catch (URISyntaxException e) {
return Mono.empty();
}
}
/**
* Removes a query param and its value from a given url
* @param url the url to be modified.
* @param queryParam the parameter to be removed.
* @return the url wihtout the query param to be removed
* or the same url in case that query param isn't in that given url
*/
public static String removeQueryParam( String url, String queryParam ) {
String result = "";
String[] urlParts = url.split("\?");
if (urlParts.length >= 2) {
String[] urlParams = urlParts[urlParts.length - 1].split("&");
for (String urlParam : urlParams) {
String[] param = urlParam.split("=");
if (!param[0].equals(queryParam)) {
result += urlParam + "&";
}
}
result = urlParts[0] + (result.length() > 0 ? "?" + result.substring(0, result.length() - 1) : "");
} else {
result = url;
}
return result;
}
然后我添加了这两条路由:
/**
* Adds custom routes to the application
*/
@Bean
public RouteLocator customRouteLocator( RouteLocatorBuilder builder,
SimpleLoggingFilter loggingFilter,
RouteServiceForwardingFilter forwardingFilter) {
return builder.routes()
.route(r ->
r.query(Constants.TOKEN).negate()
.filters(f -> {
f.filter(loggingFilter);
try {
f.redirect(HttpStatus.UNAUTHORIZED, new URL("http://www.example.com/401"));
} catch (MalformedURLException e) {
LOGGER.error(e.getMessage());
}
return f;
})
.uri("http://www.example.com/401")
.id("WITHOUT_token"))
.route(r ->
r.query(Constants.TOKEN)
.and()
.header(Constants.AUTHENTICATED).negate()
.filters(f -> {
f.filter(loggingFilter);
f.filter(forwardingFilter, Constants.ROUTE_TO_URL_FILTER_ORDER + 1);
return f;
})
.uri("http://localhost:8008")
.id("with_token"))
.build();
}
然后就解决了。我希望这对其他人有帮助。