spring - 内容类型为 application/x-www-form-urlencoded 的 @RequestParam 在 Spring Boot 2.2 中不起作用
问题描述
从 Spring Boot 2.1.10 迁移到 2.2.4 后,以下方法开始为params
参数返回 null。这不是 Spring 中的错误,因为它在我制作一个小型示例项目时起作用。它也适用于没有 Content-Type: application/x-www-form-urlencoded 的普通 GET 和 POST。
@PostMapping(path = "/test", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public void test(@RequestParam Map<String, String> params) {
System.out.println(params);
}
我发出下面的请求,该请求在一个项目中有效,但在另一个项目中无效。我试图禁用所有过滤器和参数解析器,但没有任何效果。
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d "param1=1¶m2=2" http://localhost:8080/test
任何帮助或想法将不胜感激。此外,如果有人可以指出 Spring 解决参数的地方,我可以尝试调试并查看会发生什么。
解决方案
添加另一个答案,因为我遇到了同样的问题,但以不同的方式解决了它。
我也有一个请求日志过滤器,它包装传入的请求并以与 Jonas Pedersen 的答案中描述的类似方式缓存响应输入流。Spring Boot 从 2.1.2.RELEASE 更新到 2.3.4.RELEASE
我将传入请求包装在缓存输入流的缓存请求包装器中。对我来说,问题是由于某些(目前未知)原因,request.getParameterValue(String key) 方法返回 null,即使包装的请求显然具有非空参数映射。简单地访问包装的请求参数映射为我解决了这个问题......非常奇怪。
原始包装类,使用 Spring Boot 2.1.2.RELEASE:
public class CachingRequestWrapper extends HttpServletRequestWrapper {
private final byte[] cachedBody;
public CachingRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
InputStream requestInputStream = request.getInputStream();
this.cachedBody = StreamUtils.copyToByteArray(requestInputStream);
}
@Override
public ServletInputStream getInputStream() throws IOException {
return new CachedInputStream(this.cachedBody);
}
@Override
public BufferedReader getReader() throws IOException {
ByteArrayInputStream byteArrayInputStream =
new ByteArrayInputStream(this.cachedBody);
String encoding = StringUtils.isEmpty(this.getCharacterEncoding())
? StandardCharsets.UTF_8.name()
: this.getCharacterEncoding();
return new BufferedReader(new InputStreamReader(byteArrayInputStream, encoding));
}
}
为简洁起见,省略了 CachedInputStream 类的实现。
简单地访问包装的请求图似乎解决了整个问题。对于 Spring Boot 2.3.4.RELEASE,此版本有效(我删除了一些细节):
public class CachingRequestWrapper extends HttpServletRequestWrapper {
private final byte[] cachedBody;
private final Map<String, String[]> parameterMap;
public CachingRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
parameterMap = request.getParameterMap(); // <-- This was the crucial part
InputStream requestInputStream = request.getInputStream();
this.cachedBody = StreamUtils.copyToByteArray(requestInputStream);
}
@Override
public Map<String, String[]> getParameterMap() {
return this.parameterMap; // this was added just to satisfy spotbugs
}
}
我没有费心去深入研究这个问题,所以我不能说两个 Spring Boot 版本之间发生了什么变化,或者在包装器构造函数中访问参数映射解决了什么问题。
推荐阅读
- dialogflow-cx - Dialogflow CX 代理中的文本转语音设置
- facebook - 如何获取 Facebook 主页的官方二维码?
- amazon-web-services - 通过启用 IRSA,我是否仅限于每个帐户运行 100 个 EKS 集群?
- c# - 是否可以在 HotChocolate 中创建通用数据加载器?
- python - Matplotlib 绘图函数在 conda 基本环境中挂起
- javascript - 等待函数完成做其他事情 node.js 强大
- sql - 创建新表时添加外键
- python - 使用 React 从 Azure Blob 存储下载文件
- python - 我们可以从“正在进行的”标签作业创建培训作业吗?
- python - 熊猫:在另一个数据框的另一列上设置数据框的一列的值