Spring Cloud Gateway:在自定义谓词中设置响应状态代码

Spring Cloud Gateway: Set response status code in custom predicate

在下面的代码片段中,我尝试将我的请求与自定义谓词进行匹配。当谓词被评估为 false 时,我想发回一个自定义状态代码(下面代码段中的 403 Forbidden),而不是在谓词失败时发送的默认 404。这是我试过的。

RouteLocator

@Bean
 public RouteLocator customRoutesLocator(RouteLocatorBuilder builder 
  AuthenticationRoutePredicateFactory arpf) {
    return builder.routes()
            .route("id1", r ->r.path("/app1/**")
                .uri("lb://id1")
                .predicate(arpf.apply(new Config()))).build();
}

AuthenticationRoutePredicateFactory

public class AuthenticationRoutePredicateFactory
    extends AbstractRoutePredicateFactory<AuthenticationRoutePredicateFactory.Config> {
public AuthenticationRoutePredicateFactory() {
    super(Config.class);
}

@Override
public Predicate<ServerWebExchange> apply(Config config) {

    return (ServerWebExchange t) -> {
        try {
             Boolean isRequestAuthenticated =  checkAuthenticated();

                return isRequestAuthenticated;
            }
        } catch (HttpClientErrorException e) {
           //This status code does not carried forward and 404 is displayed instead.
            t.getResponse().setStatusCode(HttpStatus.FORBIDDEN); 
            return false;
        }

    };

}

@Validated
public static class Config {

    public Config() {
    }
}

private Boolean checkAuthenticated() {
  // Some sample logic that makes a REST call and returns TRUE/FALSE/HttpClientErrorException
 //Not shown here for simplicity.
  return true;
}

}

当谓词returns为真时,请求被转发到URI。但是,在显示错误评估 404 时,我需要显示 403(在 HttpClientErrorException 上)。这是期望使用自定义状态代码进行响应的正确方法吗?此外,我还阅读了有关为给定路由实现自定义 Web 过滤器的内容,这些路由可能会在转发请求之前修改响应对象。在这种情况下,有没有办法在谓词失败时调用过滤器?

作为spring云网关的新手,我选择了错误的方向来解决这个问题。

客户端向 Spring 云网关发出请求。如果 Gateway Handler Mapping 确定请求与路由匹配,则将其发送到 Gateway Web Handler。谓词帮助网关处理程序映射确定该请求是否与路由匹配,并且只能 return truefalse 值。

一旦请求与路由匹配,处理程序就会通过特定于请求的过滤器链运行请求。这是在转发请求之前可以应用“pre”或“post”请求的地方。

因此为了在有条件地转发请求之前发送自定义响应状态代码,必须编写一个自定义“预”过滤器,这可以通过以下方式实现。 (设置403状态码)

AuthenticationGatewayFilterFactory

  @Component
 public class AuthenticationGatewayFilterFactory
    extends AbstractGatewayFilterFactory<AuthenticationGatewayFilterFactory.Config> {


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

@Override
public GatewayFilter apply(Config config) {
    return (exchange, chain) -> {
        try {
            if(isRequestAuthenticated) {
                return chain.filter(exchange);
            }
            else {
                
                exchange.getResponse().setStatusCode(403); // Any status code can be set here.
                return exchange.getResponse().complete();
            }
            

        } catch (HttpClientErrorException e) {
            exchange.getResponse().setStatusCode(403); // Any status code can be set here.
            return exchange.getResponse().complete();
        }

    };
}

public static class Config {

}

private Boolean isRequestAuthenticated(String authToken) {

// Some sample logic that makes a REST call and returns TRUE/FALSE/HttpClientErrorException
 //Not shown here for simplicity.
  return true;

}

RouteLocator

 @Bean
 public RouteLocator customRoutesLocator(RouteLocatorBuilder builder 
  AuthenticationGatewayFilterFactory agff) {
    return builder.routes()
            .route("id1", r ->r.path("/app1/**")
                .uri("lb://id1")
                .filter(agff.apply(new Config()))).build();
}