Describe the bug
正常情况下,当表单参数超过设置的大小会在此类这块代码进行判断:
并且会抛出这样的错:
高版本为413 - Request Entity Too Large
提前解析了参数,导致此变量被设置为true,后续即使表单超大也都被跳过去了。

最后却提示一个与表单超大无关的异常:
那这个异常是什么情况呢?是因为表单太大了,被截断了,而刚好token也被截断了,之后报认证失败。
我调试了代码,发现nacos在启动时会为了性能缓存了URL和默认参数,下图为默认参数解析
正因为这些默认参数,每次请求进来时都会提前解析了,导致Tomcat的Request类的变量被设置为true,后续表单参数再大也无法拦截。
Expected behavior
抛出由底层的Tomcat请求体太大的异常信息,即上述截图。
Actually behavior
A clear and concise description of what you actually to happen.
How to Reproduce
Steps to reproduce the behavior:
- 准备一个超过3MB(因为默认2MB,当然你可以调小,根据实际情况)的文件。
- 然后使用curl请求接口:
curl http://localhost:8848/nacos/v1/cs/configs \
-H 'Content-Type: application/x-www-form-urlencoded' \
-H 'Expect:' \
--data-binary @mysoft-emc-long.txt
Desktop (please complete the following information):
- OS: [e.g. Centos]
- Version 2.5.0
- Module config
Additional context
代码我已经粗略读了一遍,但为了更清晰分析问题,以下为AI输出:
ControllerMethodsCache 的作用
1. 核心功能:方法缓存和路由匹配
从代码可以看出,这个类主要做两件事:
// 缓存所有的 Controller 方法
private ConcurrentMap<RequestMappingInfo, Method> methods = new ConcurrentHashMap<>();
// URL 到方法的映射
private final ConcurrentMap<String, List<RequestMappingInfo>> urlLookup = new ConcurrentHashMap<>();
作用:
- 缓存所有 Controller 的 @RequestMapping、@GetMapping、@PostMapping 等注解的方法
- 快速查找:根据 URL 和 HTTP 方法找到对应的处理方法
- 路由匹配:支持复杂的路由条件匹配(路径、参数等)
2. 为什么需要这个类?
让我查看一下在 AuthFilter 中是如何使用的:
⏺ Read(core/src/main/java/com/alibaba/nacos/core/auth/AuthFilter.java)
⎿ Read 90 lines
⏺ 完美!现在我可以清楚地解释了。
为什么需要 ControllerMethodsCache
核心原因:在 Filter 层面进行权限控制
看 AuthFilter.java:77-90 的逻辑:
// 第77行:获取当前请求对应的 Controller 方法
Method method = methodsCache.getMethod(req);
if (method == null) {
chain.doFilter(request, response); // 不是 Controller 方法,直接放行
return;
}
// 第84行:检查方法是否有 @Secured 注解
if (method.isAnnotationPresent(Secured.class)) {
// 需要权限验证
Secured secured = method.getAnnotation(Secured.class);
// ... 进行权限验证
}
传统 Spring MVC 的问题
没有 ControllerMethodsCache 的做法:
请求 → Filter → DispatcherServlet → HandlerMapping → Controller
↑
在这里不知道请求会映射到哪个 Controller 方法
所以无法在 Filter 层判断是否需要权限验证
问题:
- Filter 在 DispatcherServlet 之前执行
- Filter 不知道请求最终会映射到哪个 Controller 方法
- 无法在 Filter 层进行方法级别的权限控制
Nacos 的解决方案
使用 ControllerMethodsCache:
请求 → Filter (AuthFilter)
├─ ControllerMethodsCache.getMethod(req) → 获取目标方法
├─ 检查 @Secured 注解
├─ 进行权限验证
└─ 验证通过 → DispatcherServlet → Controller
优势:
1. ✅ 在 Filter 层就能获取目标方法
2. ✅ 支持参数条件匹配:@RequestMapping(params="accessToken=123")
3. ✅ 性能优化:缓存了所有方法映射,不需要每次都反射扫描
4. ✅ 统一权限控制:所有带 @Secured 注解的方法都会被拦截
详细功能拆解
1. 方法缓存
// 启动时扫描并缓存所有 Controller 方法
public void initClassMethod(String packageName) {
// 扫描 @RequestMapping, @GetMapping 等注解
// 缓存到 methods 和 urlLookup 中
}
2. 路由匹配
public Method getMethod(HttpServletRequest request) {
// 1. 根据 URL 和 HTTP 方法查找候选方法
List<RequestMappingInfo> requestMappingInfos = urlLookup.get(urlKey);
// 2. 进行精细匹配(包括参数条件)
List<RequestMappingInfo> matchedInfo = findMatchedInfo(...);
// 3. 返回最佳匹配的方法
return methods.get(bestMatch);
}
3. 参数条件匹配(关键!)
这就是导致参数提前解析的原因:
private List<RequestMappingInfo> findMatchedInfo(...) {
for (RequestMappingInfo requestMappingInfo : requestMappingInfos) {
// 检查参数条件:@RequestMapping(params="key=value")
ParamRequestCondition matchingCondition = requestMappingInfo
.getParamRequestCondition()
.getMatchingCondition(request); // ⚠️ 这里会调用 getParameter()
if (matchingCondition != null) {
matchedInfo.add(requestMappingInfo);
}
}
return matchedInfo;
}
支持的参数条件示例:
@RestController
public class ConfigController {
// 只有当请求中包含 accessToken 参数且值为 admin 时才匹配
@PostMapping(value = "/config", params = "accessToken=admin")
public Result postConfig() { ... }
// 只有当请求中不包含 debug 参数时才匹配
@GetMapping("/config", params="!debug")
public Result getConfig() { ... }
}
总结
为什么需要 ControllerMethodsCache?
┌───────────────────┬───────────────────────────────────────────────┐
│ 原因 │ 说明 │
├───────────────────┼───────────────────────────────────────────────┤
│ Filter 层权限控制 │ 在请求到达 Controller 之前就进行权限验证 │
├───────────────────┼───────────────────────────────────────────────┤
│ 方法级别注解支持 │ 识别 @Secured 注解,判断是否需要权限验证 │
├───────────────────┼───────────────────────────────────────────────┤
│ 参数条件匹配 │ 支持 @RequestMapping(params="...") 的路由匹配 │
├───────────────────┼───────────────────────────────────────────────┤
│ 性能优化 │ 缓存方法映射,避免每次请求都反射扫描 │
└───────────────────┴───────────────────────────────────────────────┘
权衡
优点:
- ✅ 实现了统一的权限控制
- ✅ 支持复杂的路由匹配条件
缺点:
- ❌ 提前触发了参数解析(这就是您遇到的问题根源)
- ❌ 与 Tomcat 的 maxHttpFormPostSize 校验时机产生冲突
Describe the bug
正常情况下,当表单参数超过设置的大小会在此类这块代码进行判断:
并且会抛出这样的错:
提前解析了参数,导致此变量被设置为true,后续即使表单超大也都被跳过去了。

最后却提示一个与表单超大无关的异常:
那这个异常是什么情况呢?是因为表单太大了,被截断了,而刚好token也被截断了,之后报认证失败。
我调试了代码,发现nacos在启动时会为了性能缓存了URL和默认参数,下图为默认参数解析
正因为这些默认参数,每次请求进来时都会提前解析了,导致Tomcat的Request类的变量被设置为true,后续表单参数再大也无法拦截。
Expected behavior
抛出由底层的Tomcat请求体太大的异常信息,即上述截图。
Actually behavior
A clear and concise description of what you actually to happen.
How to Reproduce
Steps to reproduce the behavior:
Desktop (please complete the following information):
Additional context
代码我已经粗略读了一遍,但为了更清晰分析问题,以下为AI输出: