Webflux 的上下文路径
Context Path with Webflux
我一直在努力寻找一种方法来为 webflux 应用程序设置上下文路径。我知道我可以使用
配置它
server.servlet.context-path
如果我部署了一个 servlet,但我想用 webflux 来实现它,而不必显式地将路径添加到每个路由或使用 MVC。
如果您自己配置服务器(如果您不使用 Spring 引导),您可以设置 a ContextPathCompositeHandler 来包装多个处理程序本身。
如果您使用的是Spring Boot,目前不支持此功能。
我遇到了同样的问题,因为加载器平衡器基于上下文路径路由到不同的后端应用程序。绕过 Spring Boot Webflux w/上下文路径的一种方法是在 @XXXXMapping 注释中使用变量。例如@RequestMapping(value = "${server.servlet.context-path}/subpath")
对于 Undertow,我设法通过创建自定义的 UndertowReactiveWebServerFactory 添加上下文路径:
@Bean
public UndertowReactiveWebServerFactory undertowReactiveWebServerFactory(
@Value("${server.servlet.context-path}") String contextPath) {
return new UndertowReactiveWebServerFactory() {
@Override
public WebServer getWebServer(HttpHandler httpHandler) {
Map<String, HttpHandler> handlerMap = new HashMap<>();
handlerMap.put(contextPath, httpHandler);
return super.getWebServer(new ContextPathCompositeHandler(handlerMap));
}
};
}
这是我使用 Tomcat Reactive 的方法:
@Configuration
public class TomcatReactiveWebServerConfig extends TomcatReactiveWebServerFactory {
@Value("${server.servlet.context-path}")
private String contextPath;
/**
* {@inheritDoc}
*/
@Override
protected void configureContext(final Context context) {
super.configureContext(context);
if (StringUtils.isNotBlank(this.contextPath)) {
context.setPath(this.contextPath);
}
}
}
您可以使用网络过滤器让 WebFlux 支持 contextPath
@Bean
public WebFilter contextPathWebFilter() {
String contextPath = serverProperties.getServlet().getContextPath();
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
if (request.getURI().getPath().startsWith(contextPath)) {
return chain.filter(
exchange.mutate()
.request(request.mutate().contextPath(contextPath).build())
.build());
}
return chain.filter(exchange);
};
}
对于 WebFlux 应用程序落后于负载的用例 balancer/proxy 您可以使用专用的 class - ForwardedHeaderTransformer
将从 X-Forwarded-Prefix
中提取路径上下文并将其添加到ServerHttpRequest
。
这样做你不需要修改全局 context-path
(这在 WebFlux 中没有意义)
这是一个使用 Netty 服务器配置 WebFlux 上下文路径的示例,该示例基于 @Dmytro Boichenko 的评论。您还可以包括自定义程序来配置端口和其他属性。
@Configuration
public class NettyServerConfig {
@Value("${server.port}")
private int port;
@Value("${server.context.path}")
private String contextPath;
@Bean
public NettyReactiveWebServerFactory nettyReactiveWebServerFactory() {
NettyReactiveWebServerFactory webServerFactory = new NettyReactiveWebServerFactory() {
@Override
public WebServer getWebServer(HttpHandler httpHandler) {
Map<String, HttpHandler> handlerMap = new HashMap<>();
handlerMap.put(contextPath, httpHandler);
return super.getWebServer(new ContextPathCompositeHandler(handlerMap));
}
};
webServerFactory.addServerCustomizers(portCustomizer());
return webServerFactory;
}
public NettyServerCustomizer portCustomizer() {
return new NettyServerCustomizer() {
@Override
public HttpServer apply(HttpServer httpServer) {
return httpServer.port(port);
}
};
}
}
根据this
There is servlet in the name of the property which should be a
hint that won't work with webflux.
使用 springboot v2.3,你可以把它放在你的属性文件中
spring.webflux.base-path=/your-path
您可以使用网络过滤器,如上面的答案所述,但您还可以做一件事。编写一个基本控制器并将每个 class 扩展到该基本控制器。
例如:
基地Controller.java
@RestController
@RequestMapping("/{base_url}")
public abstract class BaseController {
}
新建Controller.java
@RestController
public class NewController extends BaseController{
@Autowired
DatabaseClient databaseClient;
@GetMapping("/status")
public Mono<Map<String, String>> status() {
return databaseClient.execute("SELECT 'ok'").
map(row -> singletonMap("status", row.get(0, String.class)))
.one();
}
}
所以现在你可以点击 /{base_url}/status
我在 webflux-reactive-spring-web
中遇到了与 spring.webflux.base-path
类似的问题(它似乎没有按预期工作),我意识到我禁用了自动配置。
手动解决方法是:
@Bean
public WebFluxProperties webFluxProperties(){
return new WebFluxProperties();
}
Spring webflux 版本 2.3.4.RELEASE
需要两个元素,先声明一个bean来启用weflux属性
@Bean public WebFluxProperties webFluxProperties(){
return new WebFluxProperties();
}
第二次定义正确的路径
spring.webflux.base-path = mypath
我一直在努力寻找一种方法来为 webflux 应用程序设置上下文路径。我知道我可以使用
配置它server.servlet.context-path
如果我部署了一个 servlet,但我想用 webflux 来实现它,而不必显式地将路径添加到每个路由或使用 MVC。
如果您自己配置服务器(如果您不使用 Spring 引导),您可以设置 a ContextPathCompositeHandler 来包装多个处理程序本身。
如果您使用的是Spring Boot,目前不支持此功能。
我遇到了同样的问题,因为加载器平衡器基于上下文路径路由到不同的后端应用程序。绕过 Spring Boot Webflux w/上下文路径的一种方法是在 @XXXXMapping 注释中使用变量。例如@RequestMapping(value = "${server.servlet.context-path}/subpath")
对于 Undertow,我设法通过创建自定义的 UndertowReactiveWebServerFactory 添加上下文路径:
@Bean
public UndertowReactiveWebServerFactory undertowReactiveWebServerFactory(
@Value("${server.servlet.context-path}") String contextPath) {
return new UndertowReactiveWebServerFactory() {
@Override
public WebServer getWebServer(HttpHandler httpHandler) {
Map<String, HttpHandler> handlerMap = new HashMap<>();
handlerMap.put(contextPath, httpHandler);
return super.getWebServer(new ContextPathCompositeHandler(handlerMap));
}
};
}
这是我使用 Tomcat Reactive 的方法:
@Configuration
public class TomcatReactiveWebServerConfig extends TomcatReactiveWebServerFactory {
@Value("${server.servlet.context-path}")
private String contextPath;
/**
* {@inheritDoc}
*/
@Override
protected void configureContext(final Context context) {
super.configureContext(context);
if (StringUtils.isNotBlank(this.contextPath)) {
context.setPath(this.contextPath);
}
}
}
您可以使用网络过滤器让 WebFlux 支持 contextPath
@Bean
public WebFilter contextPathWebFilter() {
String contextPath = serverProperties.getServlet().getContextPath();
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
if (request.getURI().getPath().startsWith(contextPath)) {
return chain.filter(
exchange.mutate()
.request(request.mutate().contextPath(contextPath).build())
.build());
}
return chain.filter(exchange);
};
}
对于 WebFlux 应用程序落后于负载的用例 balancer/proxy 您可以使用专用的 class - ForwardedHeaderTransformer
将从 X-Forwarded-Prefix
中提取路径上下文并将其添加到ServerHttpRequest
。
这样做你不需要修改全局 context-path
(这在 WebFlux 中没有意义)
这是一个使用 Netty 服务器配置 WebFlux 上下文路径的示例,该示例基于 @Dmytro Boichenko 的评论。您还可以包括自定义程序来配置端口和其他属性。
@Configuration
public class NettyServerConfig {
@Value("${server.port}")
private int port;
@Value("${server.context.path}")
private String contextPath;
@Bean
public NettyReactiveWebServerFactory nettyReactiveWebServerFactory() {
NettyReactiveWebServerFactory webServerFactory = new NettyReactiveWebServerFactory() {
@Override
public WebServer getWebServer(HttpHandler httpHandler) {
Map<String, HttpHandler> handlerMap = new HashMap<>();
handlerMap.put(contextPath, httpHandler);
return super.getWebServer(new ContextPathCompositeHandler(handlerMap));
}
};
webServerFactory.addServerCustomizers(portCustomizer());
return webServerFactory;
}
public NettyServerCustomizer portCustomizer() {
return new NettyServerCustomizer() {
@Override
public HttpServer apply(HttpServer httpServer) {
return httpServer.port(port);
}
};
}
}
根据this
There is servlet in the name of the property which should be a hint that won't work with webflux.
使用 springboot v2.3,你可以把它放在你的属性文件中
spring.webflux.base-path=/your-path
您可以使用网络过滤器,如上面的答案所述,但您还可以做一件事。编写一个基本控制器并将每个 class 扩展到该基本控制器。 例如:
基地Controller.java
@RestController
@RequestMapping("/{base_url}")
public abstract class BaseController {
}
新建Controller.java
@RestController
public class NewController extends BaseController{
@Autowired
DatabaseClient databaseClient;
@GetMapping("/status")
public Mono<Map<String, String>> status() {
return databaseClient.execute("SELECT 'ok'").
map(row -> singletonMap("status", row.get(0, String.class)))
.one();
}
}
所以现在你可以点击 /{base_url}/status
我在 webflux-reactive-spring-web
中遇到了与 spring.webflux.base-path
类似的问题(它似乎没有按预期工作),我意识到我禁用了自动配置。
手动解决方法是:
@Bean
public WebFluxProperties webFluxProperties(){
return new WebFluxProperties();
}
Spring webflux 版本 2.3.4.RELEASE
需要两个元素,先声明一个bean来启用weflux属性
@Bean public WebFluxProperties webFluxProperties(){
return new WebFluxProperties();
}
第二次定义正确的路径
spring.webflux.base-path = mypath