1. 引言

在开发 Web 服务时,我们经常会遇到包含斜杠 / 的复杂或非预期的 URL 路径。这类路径容易引发问题,尤其是在某些 Web 服务器或框架的默认配置下,行为可能不符合预期。

Spring 框架在这方面尤其“讲究”——它的默认配置严格遵循 URI 标准,导致处理带斜杠的路径时容易踩坑 ❌。

本文将介绍几种在 Spring 中正确处理 URL 斜杠的实用方案,✅ 并重点说明为什么某些“看似可行”的 hack 方法其实隐患极大,应坚决避免。


2. 手动解析请求路径

有时我们需要将某个路径前缀下的所有请求都路由到同一个接口,而且这个路径的后半部分是任意的,甚至结构未知。更关键的是,我们还需要把这个动态路径作为参数接收并后续处理,比如记录日志或存入数据库。

例如,我们希望捕获所有以 /mypaths 开头的请求:

http://localhost:8080/mypaths/any/custom/path

第一反应可能是使用 @PathVariable 来捕获后面的动态部分:

@GetMapping("mypaths/{anything}")
public String pathVariable(@PathVariable("anything") String anything) {
    return anything;
}

⚠️ 但很快你会发现:只要 {anything} 中包含 /,就会返回 404。

原因很简单:/ 是 URI 标准(RFC 3986)中用于分隔路径层级的分隔符。Spring 默认严格按照标准解析,不会把 / 当作普通字符处理。

✅ 正确解法:使用 ** 通配符 + 手动解析

Spring 支持 ** 通配符来匹配任意层级的路径。我们可以这样定义接口:

@GetMapping("all/**")
public String allDirectories(HttpServletRequest request) {
    return request.getRequestURI()
        .split(request.getContextPath() + "/all/")[1];
}

这样,所有 /all/ 后面的内容都会被匹配到,然后我们通过 HttpServletRequest 手动提取真实路径。

✅ 优势:简单粗暴,适用于路径前缀固定、后半部分任意的场景
❌ 缺点:需要手动解析,不够“声明式”,且无法直接用于 RESTful 路径参数


3. 使用查询参数替代路径参数

上面的方法适用于“路径映射”场景,但在另一种常见需求中——我们需要在 URL 中传递一个可能包含 / 的字符串参数——上面的方法就不够用了。

举个例子,假设我们想接收这样的请求:

http://localhost:8080/all/http://myurl.com

你可能期望后端能完整拿到 http://myurl.com,但实际得到的却是 http:/myurl.com

⚠️ 为什么?因为 Spring Security 会自动对 URL 进行规范化(normalize),其中包括:

  • 将连续的 // 替换为单个 /
  • 处理路径遍历(如 ../
  • 防止恶意构造的 URL 绕过安全规则

这是 Spring Security 的安全机制,文档详见:Spring Security 官方文档 - 请求匹配

✅ 推荐做法:改用查询参数

最稳妥的方式是避免在路径中传递含 / 的参数,改用查询参数(query parameter):

@GetMapping("all")
public String queryParameter(@RequestParam("param") String param) {
    return param;
}

请求方式变为:

http://localhost:8080/all?param=http://myurl.com

✅ 优势:

  • 不受 URL 规范化影响
  • 参数可任意编码,灵活性高
  • 更符合 REST 设计规范
  • 安全性更高,避免路径注入风险

4. 避免使用危险的“变通方案”

由于上述限制,开发者可能会尝试一些“变通”方法让原始设计继续工作,比如:

❌ 方案一:对斜杠进行编码(如 %2F

听起来合理?但现实很残酷:

  • 多数应用服务器(如 Tomcat)**默认禁止解码路径中的 %2F**,防止 CVE-2007-0450 等历史漏洞被利用
  • 即使你通过配置开启(如 Tomcat 的 allowEncodedSlash=true),也存在安全风险
  • Apache HTTP Server 虽支持 AllowEncodedSlashes NoDecode,但依然不推荐用于生产

❌ 方案二:修改 Spring 的 URL 规范化行为

Spring 提供了一些底层机制来控制 URL 处理方式,比如通过 UrlPathHelper 自定义路径解析。但:

  • 修改默认行为容易引入兼容性问题
  • 可能绕过安全防护,导致路径遍历攻击
  • 框架本身的设计就是“宁可保守,不可放纵”

📌 总结:这些“hack”看似解决了问题,实则打开了安全潘多拉魔盒。生产环境务必遵守最小权限原则,不要轻易改动默认安全配置。


5. 结论

处理 Spring 中 URL 的斜杠问题,核心原则是:

优先使用查询参数传递含 / 的字符串
✅ 若必须匹配任意路径,使用 /** 通配符 + 手动解析
❌ 避免对路径中的斜杠进行编码或修改框架/服务器的默认安全行为

🔐 安全永远比“方便”更重要。Spring 的“严格”其实是对开发者的保护。

本文所有示例代码已托管至 GitHub:
https://github.com/example/spring-web-url-demo


原始标题:Using a Slash Character in Spring URLs