Ohhnews

分类导航

$ cd ..
Baeldung原文

如何配置 Spring Boot 将 404 错误重定向至单页应用(SPA)

#spring boot#单页应用#路由配置#后端开发#错误处理

[LOADING...]

1. 简介

单页应用(SPA,如使用 ReactAngularVue 构建的应用)通常依赖于客户端路由。当从 Spring Boot 后端提供服务时,刷新页面或访问错误的链接会发送一个指向服务器不存在路径的请求,导致 Spring Boot 返回 404 错误。

为了使 SPA 正常工作,我们需要将所有未匹配的请求转发至 index.html 并返回 HTTP 200 状态码,从而让前端路由器处理该路径。

在本教程中,我们将学习如何配置 Spring Boot,以便将所有未知路由重定向到 SPA 的 index.html

2. Maven 依赖

首先,在 pom.xml 中引入 spring-boot-starter-web 依赖:

$ xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>3.3.2</version>
</dependency>

3. 使用 Spring Boot 搭建基础 SPA

假设我们有一个由 Spring Boot 部署的 SPA,其编译后的前端文件放置在 resources 目录下:

$ plaintext
src/main/resources/static

例如,一个极简的 index.html 可能如下所示:

$ xml
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Baeldung</title>
</head>
<body>
    <h1>Home Page</h1>
</body>
</html>

接下来,我们创建一个简单的控制器来转发根路径:

$ java
@Controller
public class HomeController {
    @RequestMapping("/")
    public String getHome(){
        return "forward:/index.html";
    }
}

当用户访问根路径 http://localhost:8080/ 时,Spring Boot 会正确加载 index.html

然而,如果用户刷新了某个客户端路由(例如 *http://localhost:8080/dashboard*),Spring Boot 会尝试查找 /dashboard 的服务器映射,并返回 404 Not Found。我们希望 Spring Boot 返回 index.html,以便由 SPA 路由器处理该路由。

4. 重定向 404 Not Found 错误

本节介绍几种将未匹配请求重定向到 index.html 的解决方案。

4.1. 使用控制器转发未知路由

我们可以创建一个控制器,将所有未映射的路径转发至 index.html

$ java
@Controller
public class SpaForwardController {
    @RequestMapping(value = "/{path:[^\\.]*}")
    public String redirect() {
        return "forward:/";
    }
}

不包含文件扩展名的未匹配请求会被转发至 "/",从而返回 index.html

如果存在具体的映射(例如 @GetMapping("/dashboard")),Spring 会优先选择该映射,而忽略此全匹配模式。对于任何其他没有匹配处理器(如 /settings)的路径,请求会落入全匹配映射并被转发至 index.html

此外,我们还需要支持更深层的路由,如 /dashboard/settings。为此,可以扩展控制器的映射:

$ java
@Controller
public class SpaForwardController {
    @RequestMapping(value = {
        "/{path:[^\\.]*}",
        "/{path:[^\\.]*}/**/{subpath:[^\\.]*}"
    })
    public String redirect() {
        return "forward:/";
    }
}

4.2. 使用自定义错误控制器

另一种方法是拦截 404 错误并将其重定向到 SPA 入口点

$ java
@Controller
public class SpaErrorController implements ErrorController {
    @RequestMapping("/error")
    public String handleError() {
        return "forward:/index.html";
    }
}

这种方法可以确保任何未知路由最终都能加载 SPA。

然而,该方法也可能会拦截真实的后端 404 错误,这在某些场景下可能并不理想。

4.3. 使用 WebMvcConfigurer

另一种方法是集中处理错误,避免显式匹配路由模式

我们可以通过实现 WebMvcConfigurer 接口并注册自定义错误页面来实现:

$ java
@Configuration
public class WebApplicationConfig implements WebMvcConfigurer {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/notFound")
          .setViewName("forward:/index.html");
    }
    @Bean
    public WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> containerCustomizer() {
        return container -> {
            container.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/notFound"));
        };
    }
}

在此配置中,任何导致 404 Not Found 错误的请求都会被重定向到 /notFound。该端点随后会将请求转发至 index.html

同样需要注意,这意味着所有的 404 错误(包括后端 API 的错误)都会被重定向到 SPA,这未必总是我们想要的结果。

5. 测试

启动 Spring Boot 应用后,我们可以通过访问不同的 URL 来验证配置。

首先,请求根路径:

$ plaintext
$ curl -i http://localhost:8080/

响应返回 200 以及 index.html 的内容:

$ plaintext
HTTP/1.1 200
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Baeldung</title>
</head>
<body>
    <h1>Home Page</h1>
</body>
</html>

接下来,模拟访问一个客户端路由:

$ plaintext
$ curl -i http://localhost:8080/dashboard

应用返回 200 并提供了 index.html,而不是 404 Not Found。这证明请求已被正确转发并由 SPA 路由器处理。

6. 结论

在本文中,我们探讨了在使用 Spring Boot 提供单页应用服务时,如何将未知路由转发至 index.html。我们研究了多种方法,包括使用自定义控制器、配置 WebMvcConfigurer 以及通过自定义错误映射处理错误。

一如既往,源代码可在 GitHub 上找到。