英文:
Problems about comsuming request body for multiple times
问题
我是一名新的Java开发者。最近,我正在开发一个新的Spring Boot项目,我想在进入MVC控制器之前打印请求体(确切地说,我想打印具有contentType:"application/json"的POST请求的请求体)。
我使用以下的请求包装器(RequestWrapper):
public class MyRequestWrapper extends HttpServletRequestWrapper {
private byte[] cachedBody = new byte[]{};
private InputStream input = null;
public MyRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
if (request.getContentType() != null && (request.getContentType().contains("multipart/") ||
request.getContentType().contains("/x-www-form-urlencoded"))) {
cachedBody = new byte[]{};
input = request.getInputStream();
} else {
cachedBody = StreamUtils.copyToByteArray(request.getInputStream());
input = new ByteArrayInputStream(cachedBody);
}
}
@Override
public ServletInputStream getInputStream() {
return new ServletInputStream() {
@Override
public int read() throws IOException {
return input.read();
}
};
}
public String getBody() {
return new String(cachedBody);
}
}
然后,我使用一个过滤器来打印请求内容:
@WebFilter(filterName = "RequestResponseFilter", urlPatterns = "/*", asyncSupported = true)
public class RequestResponseFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
MyRequestWrapper requestWrapper = (MyRequestWrapper) request;
// ...
System.out.println(requestWrapper.getBody());
// ...
chain.doFilter(requestWrapper, response);
}
}
以下是我的控制器:
@PostMapping(value="/test")
public ResponseData<String> test(
@RequestParam("id") String id,
@RequestParam("value") String value) {
ResponseData<String> result = new ResponseData<>();
result.setData(id + value);
result.setCode(Constants.CODE_SUCCESS);
return result;
}
然而,当我使用Postman测试我的代码时,它没有正常工作。如果我使用POST方法并传递参数,同时设置内容类型为"application/x-www-form-urlencoded",它会抛出"org.springframework.web.bind.MissingServletRequestParameterException"异常。
让我困惑的是,如果我使用内容类型"multipart/form-data"传递参数,它却能正常工作。
此外,我尝试过使用Spring提供的CachedBodyHttpServletRequest,但直到请求进入控制器之前,它都无法获取请求内容。
为什么MVC控制器无法正常获取带有@RequestParam注解的参数?我该如何修复它?
英文:
I'm a new javaer. Recently I'm working on a new springboot project, and I want to print request body before it enter mvc controller. (To be exact, I want to print request body of post request with contentType:"application/json")
I use a requestWrapper as below.
public class MyRequestWrapper extends HttpServletRequestWrapper {
private byte[] cachedBody = new byte[]{};
private InputStream input = null;
public MyRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
if (request.getContentType() != null && (request.getContentType().contains("multipart/") ||
request.getContentType().contains("/x-www-form-urlencoded"))) {
cachedBody = new byte[]{};
input = request.getInputStream();
} else {
cachedBody = StreamUtils.copyToByteArray(request.getInputStream());
input = new ByteArrayInputStream(cachedBody);
}
}
@Override
public ServletInputStream getInputStream() {
return new ServletInputStream() {
@Override
public int read() throws IOException {
return input.read();
}
}
}
public String getBody() {
return new String(cachedBody);
}
Then, I use a filter to print the request content.
@WebFilter(filterName = "RequestResponseFilter", urlPatterns = "/*", asyncSupported = true)
public class RequestResponseFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
MyRequestWrapper requestWrapper = (MyRequestWrapper) request;
......
System.out.println(requestWrapper.getBody());
......
chain.doFilter(requestWrapper, response);
}
}
Below is my controller.
@PostMapping(value="/test")
public ResponseData<String> test(
@RequestParam("id") String id,
@RequestParam("value") String value) {
ResponseData<String> result = new ResponseData<>();
result.setData(id + value);
result.setCode(Constants.CODE_SUCCESS);
return result;
}
However, when I use postman to test my code, it didn't work well. If I use post method and pass param with content-type:"application/x-www-form-urlencoded", it throws "org.springframework.web.bind.MissingServletRequestParameterException".
What confuse me is that, if I pass param with content-type:"multipart/form-data", it work well.
Besides, I have tried CachedBodyHttpServletRequest which provided by spring. But it couldn't get request content until the request enter controller.
Why the mvc controller failed to get param with annotation @RequestParam? And how can I fix it?
答案1
得分: 1
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// param
request.getParameterMap().forEach((k, v) -> System.out.println(k + " : " + v[0]));
// body
byte[] array = StreamUtils.copyToByteArray(request.getInputStream());
System.out.println(new String(array, StandardCharsets.UTF_8));
}
但如果您使用multipart/form-data
上传文件,则文件内容无法转换为字符串,您需要工具来解决这个问题,类似于以下内容:
if (contentType.startsWith("multipart/form-data")) {
StandardServletMultipartResolver resolver = new StandardServletMultipartResolver();
StandardMultipartHttpServletRequest req = (StandardMultipartHttpServletRequest) resolver.resolveMultipart((HttpServletRequest) request);
System.out.println(req.getMultiFileMap());
System.println(req.getParameterMap());
}
英文:
u can get param & body like this
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// param
request.getParameterMap().forEach((k, v) -> System.out.println(k + " : " + v[0]));
// body
byte[] array = StreamUtils.copyToByteArray(request.getInputStream());
System.out.println(new String(array, StandardCharsets.UTF_8));
}
but if u upload file with multipart/form-data
then file content can't cast to String, u need tools to resolve it, something like this
if (contentType.startsWith("multipart/form-data")) {
StandardServletMultipartResolver resolver = new StandardServletMultipartResolver();
StandardMultipartHttpServletRequest req = (StandardMultipartHttpServletRequest)resolver.resolveMultipart((HttpServletRequest) request);
System.out.println(req.getMultiFileMap());
System.out.println(req.getParameterMap());
}
答案2
得分: 0
你可以在这里阅读文章:链接
但对于multipart/form-data,将类更改为扩展以下内容:
public class CachedBodyHttpServletFormRequest extends StandardMultipartHttpServletRequest {}
英文:
You can read article here: Link
But with multipart/form-data, change class to extend below:
public class CachedBodyHttpServletFormRequest extends StandardMultipartHttpServletRequest {}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论