如何使用 html 5 模式和 Spring webflux 处理页面刷新

bal*_*teo 4 spring-webflux angular-router

我正在尝试实现这里描述的技术:使用带有 webflux 的servlet 的 html5 模式

简而言之,用户需要能够从浏览器刷新页面,而不会404从 Spring Boot重定向到白标签页面。

上面的教程依赖于使用 servletforward:机制的技术:

@Controller
public class ForwardController {

    @RequestMapping(value = "/**/{[path:[^\\.]*}")
    public String redirect() {
        // Forward to home page so that route is preserved.
        return "forward:/";
    }
} 
Run Code Online (Sandbox Code Playgroud)

但是我使用webflux而不是servlets。这是我尝试使用的方法WebFilter

@Component
public class SpaWebFilter implements WebFilter {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        String path = exchange.getRequest().getURI().getPath();
        if (!path.startsWith("/api") && path.matches("[^\\\\.]*")) {
            return chain.filter(
                exchange.mutate().request(exchange.getRequest().mutate().path("/").build()
                ).build());
        }
        return chain.filter(exchange);
    }
}
Run Code Online (Sandbox Code Playgroud)

当用户刷新页面时,这会导致404.

编辑:让我更详细地描述这个问题:

在浏览器中加载 SPA 后,用户可以使用角度路由链接进行导航。说从 http://localhost:8080/http://localhost:8080/user-list(这里/user-list是一个角度路线。这个导航与后端没有交互。

现在,当用户 - 仍在/user-list路由上 - 选择刷新浏览器页面时,Spring 将尝试解析/user-list后端处理程序/路由器函数的路径,这将导致 Spring Boot 提供的 404 白标签错误页面。

我想要实现的是,http://localhost:8080/user-list当用户刷新浏览器页面时,页面仍然显示给用户。

编辑 2:请注意,索引页 ( http://localhost:8080/)上不会出现此刷新问题,因为我已实施此过滤器:

@Component
public class IndexWebFilter implements WebFilter {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        if (exchange.getRequest().getURI().getPath().equals("/")) {
            return chain.filter(
                exchange.mutate().request(exchange.getRequest().mutate().path("/index.html").build()
                ).build()
            );
        }
        return chain.filter(exchange);
    }
}
Run Code Online (Sandbox Code Playgroud)

为我的每个 Angular 路由实现一个这样的过滤器显然是不可行的......

编辑 3:另请注意,出现此问题是因为前端作为后端类路径上的 jar 使用以下配置:

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**").addResourceLocations("classpath:/");
        registry.addResourceHandler("/").addResourceLocations("classpath:/index.html");
    }
}
Run Code Online (Sandbox Code Playgroud)

换句话说,我既不使用前端代理也不使用反向代理(例如 nginx)

bal*_*teo 5

我已经找到了解决我的问题的方法。我弄错的是“转发”到的网址的值。

通过使用/index.html代替/,应用程序按预期运行。

@Component
public class SpaWebFilter implements WebFilter {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        String path = exchange.getRequest().getURI().getPath();
        if (!path.startsWith("/api") && path.matches("[^\\\\.]*")) {
            return chain.filter(
                exchange.mutate().request(exchange.getRequest().mutate().path("/index.html").build()
                ).build());
        }
        return chain.filter(exchange);
    }
}
Run Code Online (Sandbox Code Playgroud)

同样可以通过 NGINX 实现,如下所示:

location / {
    try_files $uri $uri/ /index.html;
}
Run Code Online (Sandbox Code Playgroud)

这假设角度路由不能包含任何点并且不能以/api前缀开头。