Spring ServletUriComponentsBuilder查询参数方括号解码问题咨询
我之前也踩过这个坑!ServletUriComponentsBuilder.fromCurrentRequest()确实会在处理编码后的参数名时犯轴——它直接照搬原始查询字符串里的编码内容,不会自动解码后再生成符合预期的链接。比如你说的page%5Bnumber%5D=2这种请求,生成的分页链接还是会带着%5B%5D,而不是我们想要的page[number]格式,哪怕Spring Data本身两种参数都支持。
解决思路:手动重构请求参数
核心就是绕过fromCurrentRequest()直接读取原始编码的问题,改用从ServletRequest中获取已经解码后的参数名,再重新构建UriComponentsBuilder:
- 先获取当前的HttpServletRequest
// 从请求上下文拿到当前请求 HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
- 基于请求URL构建空的UriComponentsBuilder
UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(request.getRequestURL().toString());
- 遍历所有已解码的参数,添加到builder中
这里关键是request.getParameterNames()返回的是解码后的参数名(比如page[number]而不是page%5Bnumber%5D),所以直接添加就能得到可读性好的参数格式:
Enumeration<String> paramNames = request.getParameterNames(); while (paramNames.hasMoreElements()) { String paramName = paramNames.nextElement(); // 处理多值参数的情况 for (String paramValue : request.getParameterValues(paramName)) { builder.queryParam(paramName, paramValue); } }
- 修改分页参数,生成上/下一页链接
比如当前页码是currentPage,上一页就是currentPage - 1,下一页是currentPage + 1:
// 生成上一页链接 builder.replaceQueryParam("page[number]", currentPage - 1); String prevPageUrl = builder.build().toUriString(); // 生成下一页链接(若需复用builder,注意参数覆盖逻辑) builder.replaceQueryParam("page[number]", currentPage + 1); String nextPageUrl = builder.build().toUriString();
为什么这个方法有效?
因为HttpServletRequest的getParameterNames()和getParameterValues()已经帮我们完成了参数的解码工作,而fromCurrentRequest()是直接读取原始的queryString(编码后的内容),所以两者生成的链接格式会不一样。用这种方式构建的链接,不管原始请求是编码还是未编码的参数格式,最终生成的分页链接都会统一使用page[number]这种可读性更好的格式。
额外提示
如果你的项目里用了Spring Data的PagedResourcesAssembler,其实可以通过自定义UriComponentsContributor来更优雅地处理这个问题,但上面的手动方法更直接,适合快速解决问题。
内容的提问来源于stack exchange,提问作者Marcel Overdijk
相关产品推荐
相关产品推荐

