编写自定义谓词和过滤器

Spring Cloud Gateway Server MVC 使用 Spring WebMvc.fn API(javadoc)作为 API Gateway 功能的基础。

Spring Cloud Gateway Server MVC 可使用这些 API 进行扩展。用户通常希望编写 RequestPredicateHandlerFilterFunction 的自定义实现,以及 HandlerFilterFunction 的两种变体,一种用于“之前”过滤器,另一种用于“之后”过滤器。

基础

Spring WebMvc.fn API 的最基本接口是 ServerRequestjavadoc)和 ServerResponsejavadoc)。它们提供了对 HTTP 请求和响应所有部分的访问。

Spring WebMvc.fn 文档声明“`ServerRequest` 和 ServerResponse 是不可变接口。在某些情况下,Spring Cloud Gateway Server MVC 必须提供替代实现,以便某些内容可以实现可变性,以满足 API 网关的代理要求。

实现 RequestPredicate

Spring WebMvc.fn RouterFunctions.Builder 需要一个 RequestPredicatejavadoc)来匹配给定的 路由RequestPredicate 是一个函数式接口,因此可以用 lambda 实现。要实现的方法签名是

boolean test(ServerRequest request)

RequestPredicate 示例实现

在此示例中,我们将展示一个谓词的实现,用于测试特定 HTTP 头是否是 HTTP 请求的一部分。

Spring WebMvc.fn 中的 RequestPredicatesGatewayRequestPredicates 中的 RequestPredicate 实现都作为 static 方法实现。我们将在此处执行相同的操作。

SampleRequestPredicates.java
import org.springframework.web.servlet.function.RequestPredicate;

class SampleRequestPredicates {
    public static RequestPredicate headerExists(String header) {
		return request -> request.headers().asHttpHeaders().containsKey(header);
    }
}

该实现是一个简单的 lambda,它将 ServerRequest.Headers 对象转换为更丰富的 HttpHeaders API。这允许谓词测试命名 header 的存在。

如何使用自定义 RequestPredicate

要使用我们新的 headerExists RequestPredicate,我们需要将其插入到 RouterFunctions.Builder 上的适当方法中,例如 route()。当然,headerExists 方法中的 lambda 可以在下面的示例中内联编写。

RouteConfiguration.java
import static SampleRequestPredicates.headerExists;
import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri;
import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route;
import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http;

@Configuration
class RouteConfiguration {

    @Bean
    public RouterFunction<ServerResponse> headerExistsRoute() {
        return route("header_exists_route")
            .route(headerExists("X-Green"), http())
            .before(uri("https://example.org"))
            .build();
    }
}

当 HTTP 请求具有名为 X-Green 的头时,上述路由将被匹配。

编写自定义 HandlerFilterFunction 实现

RouterFunctions.Builder 有三个选项可以添加过滤器:filterbeforeafterbeforeafter 方法是通用 filter 方法的特殊化。

实现 HandlerFilterFunction

filter 方法接受一个 HandlerFilterFunction 作为参数。HandlerFilterFunction<T extends ServerResponse, R extends ServerResponse> 是一个函数式接口,因此可以用 lambda 实现。要实现的方法签名是

R filter(ServerRequest request, HandlerFunction<T> next)

这允许访问 ServerRequest,并在调用 next.handle(request) 后访问 ServerResponse

HandlerFilterFunction 示例实现

此示例将展示向请求和响应都添加一个头。

SampleHandlerFilterFunctions.java
import org.springframework.web.servlet.function.HandlerFilterFunction;
import org.springframework.web.servlet.function.ServerRequest;
import org.springframework.web.servlet.function.ServerResponse;

class SampleHandlerFilterFunctions {
	public static HandlerFilterFunction<ServerResponse, ServerResponse> instrument(String requestHeader, String responseHeader) {
		return (request, next) -> {
			ServerRequest modified = ServerRequest.from(request).header(requestHeader, generateId()).build();
			ServerResponse response = next.handle(modified);
			response.headers().add(responseHeader, generateId());
			return response;
		};
	}
}

首先,从现有请求创建一个新的 ServerRequest。这允许我们使用 header() 方法添加头。然后我们调用 next.handle() 并传入修改后的 ServerRequest。然后使用返回的 ServerResponse 向响应添加头。

如何使用自定义 HandlerFilterFunction 实现

RouteConfiguration.java
import static SampleHandlerFilterFunctions.instrument;
import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri;
import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route;
import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http;

@Configuration
class RouteConfiguration {

    @Bean
    public RouterFunction<ServerResponse> instrumentRoute() {
		return route("instrument_route")
                .GET("/**", http())
				.filter(instrument("X-Request-Id", "X-Response-Id"))
                .before(uri("https://example.org"))
                .build();
    }
}

上述路由将向请求添加 X-Request-Id 头,并向响应添加 X-Response-Id 头。

编写自定义 Before 过滤器实现

before 方法接受一个 Function<ServerRequest, ServerRequest> 作为参数。这允许创建具有更新数据的新 ServerRequest 以从函数返回。

Before 函数可以通过 HandlerFilterFunction.ofRequestProcessor() 适配为 HandlerFilterFunction 实例。

Before 过滤器示例实现

在此示例中,我们将向请求添加一个具有生成值的头。

SampleBeforeFilterFunctions.java
import java.util.function.Function;
import org.springframework.web.servlet.function.ServerRequest;

class SampleBeforeFilterFunctions {
	public static Function<ServerRequest, ServerRequest> instrument(String header) {
		return request -> ServerRequest.from(request).header(header, generateId()).build();
	}
}

从现有请求创建一个新的 ServerRequest。这允许我们使用 header() 方法添加头。此实现比 HandlerFilterFunction 简单,因为我们只处理 ServerRequest

如何使用自定义 Before 过滤器实现

RouteConfiguration.java
import static SampleBeforeFilterFunctions.instrument;
import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri;
import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route;
import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http;

@Configuration
class RouteConfiguration {

    @Bean
    public RouterFunction<ServerResponse> instrumentRoute() {
        return route("instrument_route").GET("/**", http())
            .before(uri("https://example.org"))
            .before(instrument("X-Request-Id"))
            .build();
    }
}

上述路由将向请求添加 X-Request-Id 头。请注意使用 before() 方法,而不是 filter()

编写自定义 After 过滤器实现

after 方法接受一个 BiFunction<ServerRequest,ServerResponse,ServerResponse>。这允许访问 ServerRequestServerResponse,并且能够返回一个带有更新信息的新 ServerResponse

After 函数可以通过 HandlerFilterFunction.ofResponseProcessor() 适配为 HandlerFilterFunction 实例。

After 过滤器示例实现

在此示例中,我们将向响应添加一个具有生成值的头。

SampleAfterFilterFunctions.java
import java.util.function.BiFunction;
import org.springframework.web.servlet.function.ServerRequest;
import org.springframework.web.servlet.function.ServerResponse;

class SampleAfterFilterFunctions {
	public static BiFunction<ServerRequest, ServerResponse, ServerResponse> instrument(String header) {
		return (request, response) -> {
			response.headers().add(header, generateId());
			return response;
		};
	}
}

在这种情况下,我们只是将头添加到响应并返回它。

如何使用自定义 After 过滤器实现

RouteConfiguration.java
import static SampleAfterFilterFunctions.instrument;
import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri;
import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route;
import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http;

@Configuration
class RouteConfiguration {

    @Bean
    public RouterFunction<ServerResponse> instrumentRoute() {
        return route("instrument_route")
            .GET("/**", http())
            .before(uri("https://example.org"))
            .after(instrument("X-Response-Id"))
            .build();
    }
}

上述路由将向响应添加 X-Response-Id 头。请注意使用 after() 方法,而不是 filter()

如何注册自定义谓词和过滤器以进行配置

要在外部配置中使用自定义谓词和过滤器,您需要创建一个特殊的 Supplier 类并将其注册为应用程序上下文中的 bean。

注册自定义谓词

要注册自定义谓词,您需要实现 PredicateSupplierPredicateDiscoverer 查找返回 RequestPredicates 的静态方法以进行注册。

SampleFilterSupplier.java

import org.springframework.cloud.gateway.server.mvc.predicate.PredicateSupplier;

class SamplePredicateSupplier implements PredicateSupplier {

	@Override
	public Collection<Method> get() {
		return Arrays.asList(SampleRequestPredicates.class.getMethods());
	}

}

要注册 PredicateSupplier 以便在配置文件中使用,您需要将该类添加为 bean,如以下示例所示

PredicateConfiguration.java
@Configuration
class PredicateConfiguration {

    @Bean
    public SamplePredicateSupplier samplePredicateSupplier() {
        return new SamplePredicateSupplier();
    }
}

将类添加到 META-INF/spring.factories 的要求已弃用,并将在下一个主要版本中删除。

META-INF/spring.factories
org.springframework.cloud.gateway.server.mvc.predicate.PredicateSupplier=\
  com.example.SamplePredicateSupplier

注册自定义过滤器

SimpleFilterSupplier 允许轻松注册自定义过滤器。FilterDiscoverer 查找返回 HandlerFilterFunction 的静态方法以进行注册。如果您需要比 SimpleFilterSupplier 更大的灵活性,可以直接实现 FilterSupplier

SampleFilterSupplier.java
import org.springframework.cloud.gateway.server.mvc.filter.SimpleFilterSupplier;

class SampleFilterSupplier extends SimpleFilterSupplier {

    public SampleFilterSupplier() {
		super(SampleAfterFilterFunctions.class);
	}
}

要注册 FilterSupplier 以便在配置文件中使用,您需要将该类添加为 bean,如以下示例所示

FilterConfiguration.java
@Configuration
class FilterConfiguration {

    @Bean
    public SampleFilterSupplier sampleFilterSupplier() {
        return new SampleFilterSupplier();
    }
}

将类添加到 META-INF/spring.factories 的要求已弃用,并将在下一个主要版本中删除。

META-INF/spring.factories
org.springframework.cloud.gateway.server.mvc.filter.FilterSupplier=\
  com.example.SampleFilterSupplier
© . This site is unofficial and not affiliated with VMware.