【问题标题】:Spring Cloud Gateway custom routeSpring Cloud Gateway 自定义路由
【发布时间】:2018-08-13 11:41:17
【问题描述】:

我正在尝试使用 Spring Cloud Gateway 为以下场景定义路由:

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();
    }
}

}

【问题讨论】:

    标签: routes spring-cloud-gateway


    【解决方案1】:

    所以在四处寻找之后,我想出了这个实现,它完全符合我的要求。

    我像这样编辑了问题中描述的过滤器:

    /**
     * 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();
    }
    

    这就解决了。我希望这对其他人有帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-07-01
      • 2019-08-03
      • 2019-03-31
      • 2023-01-21
      • 1970-01-01
      • 2019-09-23
      • 2021-11-19
      • 2023-04-02
      相关资源
      最近更新 更多