Spring Boot 3 控制器处理带尾部斜杠问题的 POST 请求

Raf*_*afi 3 trailing-slash spring-boot spring-boot-3

我的 Spring Boot 应用程序面临一个问题,其中我有一个仅处理 POST 请求的控制器。application.yml我已经在我的as中设置了上下文路径server.servlet.context-path: /context/path。目标是处理/context/path/context/path/URL 的 POST 请求。

我的控制器看起来像这样:

@RestController
@RequestMapping("")
public class MyController {

    @PostMapping({ "", "/" })
    public ResponseEntity<String> handlePostRequest() {
        // Handling POST request logic
        return ResponseEntity.ok("POST request handled");
    }
}
Run Code Online (Sandbox Code Playgroud)

当我向 发送 POST 请求时/context/path,它会被重定向为 302 状态代码,并且请求方法更改为 GET,并且会被重定向到/context/path/.

我尝试过@RequestMapping和的不同组合PostMapping。什么都没起作用。

我找到了一些推荐的解决方案来创建 WebConfiguration 并覆盖 configurePathMatch 方法。setUseTrailingSlashMatch但类似或 的方法setMatchOptionalTrailingSeparator已被弃用。

尽管做出了这些尝试,问题仍然存在。如何配置我的应用程序来处理带或不带尾部斜杠的请求?任何有关解决此问题的见解或建议将不胜感激。

Sle*_*vin 5

迁移到 Spring Boot 3 以及相应的 Spring Framework 6 都带来了重大变化。其中之一是尾部斜杠匹配的配置选项已被声明弃用

有几个选项可以解决这个问题:

  • 在 SecurityFilterChain 中使用重定向过滤器
  • 明确声明所有支持的路由(带或不带尾部斜杠)-> 我的个人偏好
  • 使用请求包装过滤器在内部遵循正确的路线,无需请求重定向
  • 在 servlet 容器级别使用 URL 重写过滤器(例如Tuckey
  • 在服务器级别使用 URL 重写引擎(例如 Apache mod_rewrite)

对于大多数应用程序来说,以某种方式额外硬编码尾部斜杠的路径并不难。您只需找到您喜欢的方式将它们放入端点声明中即可。由于大多数应用程序都有 10 条左右的硬路由,并且几乎所有其他路由都是通过PathVariables 动态生成的,因此管理如此数量的端点是完全可能的。

但是,如果您想在应用程序级别处理这种情况,可以在此处添加一个正确的工作重定向过滤器SecurityFilterChain

public class TrailingSlashRedirectFilter extends OncePerRequestFilter {

    private static final Logger logger = LoggerFactory.getLogger(TrailingSlashRedirectFilter.class);

    @Override
    protected void doFilterInternal(
            HttpServletRequest request,
            HttpServletResponse response,
            FilterChain filterChain) throws ServletException, IOException {

        /* We want to obtain the complete request URL including the query string */
        String url = ServletUriComponentsBuilder.fromRequest(request).build().toUriString();
        String path = request.getRequestURI();
        String fixedUrl = "";

        if (url.endsWith("/") && path.length() > 1 /* not the root path */)
            fixedUrl = url.substring(0, url.length() - 1);

        if (path.isEmpty() /* root path without '/' */)
            fixedUrl = url + "/";

        if (!fixedUrl.isEmpty()) {
            response.setHeader(HttpHeaders.LOCATION, fixedUrl);
            response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
            logger.trace("Redirecting with HttpStatus 301 for requested URL '{}' to '{}'", url, fixedUrl);
        } else {
            filterChain.doFilter(request, response);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你只需这样添加它:

public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

    return http
        //...

        .addFilterBefore(new TrailingSlashRedirectFilter(), DisableEncodeUrlFilter.class)

        //...


        .build();
    }
Run Code Online (Sandbox Code Playgroud)