记一次post请求参数读取问题

本文介绍了如何在SpringMvc中处理非表单形式的Json数据,包括使用@RequestBody注解接收实体类、request.getInputStream()或getReader()读取输入流的方法,并提供了相关代码示例。同时提到了一个参考博客以供读者参考。

结论

因为请求的内容编码不是表单数据,而是Json类型的数据。所以通过

String wsid = request.getParameter("wsid");

获取的内容为空。

解决

(1)可以通过该SpringMvc的注解@RequestBody的实体类来接受。
(2)也可以通过:

request.request.getInputStream()

或者

request.request.getReader()

具体实现如下

		String  result = "";
		String line;
		while ((line = request.getReader()) != null) {
			result += line;
		}

参考

博客

在SpringMVC或Spring Boot项目中,拦截器(Interceptor)常用于对请求进行预处理,例如权限校验、日志录等。然而,当在拦截器中读取`HttpServletRequest`的请求体(如通过`getInputStream()`或`getReader()`方法)时,会遇到一个常见问题:**请求体中的数据只能读取一次**。这是由于HTTP请求的输入流本质上是一个只能读取一次的流(`ServletInputStream`),一旦读取完成,流的指针已经到达末尾,无法再次读取。 ### 问题原因 HTTP请求的输入流(如POST请求的body)在底层是以流的形式传输的,而`ServletInputStream`不支持重复读取。当在拦截器中读取了该流后,流的指针已经移动到了末尾,后续Controller层在尝试读取时会得到一个空流,从而导致数据丢失或解析失败[^5]。 ### 解决方案 为了解决这个问题,通常采用以下几种方式: #### 1. 使用`HttpServletRequestWrapper`缓存请求体 通过自定义一个`HttpServletRequestWrapper`的子类,将请求体中的数据缓存到内存中,使得在拦截器和Controller层都能多次读取。 ```java public class CachedBodyHttpServletRequest extends HttpServletRequestWrapper { private byte[] cachedBody; public CachedBodyHttpServletRequest(HttpServletRequest request) throws IOException { super(request); // 读取原始请求体内容并缓存 InputStream requestInputStream = request.getInputStream(); this.cachedBody = StreamUtils.readStream(requestInputStream); } @Override public ServletInputStream getInputStream() { return new CachedBodyServletInputStream(this.cachedBody); } @Override public BufferedReader getReader() { ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(this.cachedBody); InputStreamReader inputStreamReader = new InputStreamReader(byteArrayInputStream); return new BufferedReader(inputStreamReader); } } ``` 同时定义一个`CachedBodyServletInputStream`类来支持多次读取: ```java public class CachedBodyServletInputStream extends ServletInputStream { private ByteArrayInputStream byteArrayInputStream; public CachedBodyServletInputStream(byte[] cachedBody) { this.byteArrayInputStream = new ByteArrayInputStream(cachedBody); } @Override public int read() { return this.byteArrayInputStream.read(); } @Override public boolean isFinished() { return byteArrayInputStream.available() == 0; } @Override public boolean isReady() { return true; } @Override public void setReadListener(ReadListener readListener) { throw new UnsupportedOperationException(); } } ``` #### 2. 在过滤器中替换请求对象 在过滤器中将原始的`HttpServletRequest`替换为自定义的`CachedBodyHttpServletRequest`,这样在后续的拦截器和Controller中都可以读取到缓存后的请求体。 ```java public class RequestCachingFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpServletRequest = (HttpServletRequest) request; if ("POST".equalsIgnoreCase(httpServletRequest.getMethod())) { CachedBodyHttpServletRequest wrappedRequest = new CachedBodyHttpServletRequest(httpServletRequest); chain.doFilter(wrappedRequest, response); } else { chain.doFilter(request, response); } } } ``` 然后在Spring Boot配置类中注册该过滤器: ```java @Configuration public class FilterConfig { @Bean public FilterRegistrationBean<RequestCachingFilter> requestCachingFilter() { FilterRegistrationBean<RequestCachingFilter> registration = new FilterRegistrationBean<>(); registration.setFilter(new RequestCachingFilter()); registration.addUrlPatterns("/*"); return registration; } } ``` #### 3. 使用`@RequestBodyAdvice`进行统一处理 对于RESTful接口,可以结合`@RequestBodyAdvice`实现对请求体的统一处理,避免在拦截器中直接读取流[^3]。 --- ### 总结 通过使用`HttpServletRequestWrapper`缓存请求体,并在过滤器中替换原始请求对象,可以在不破坏原有Spring MVC处理流程的前提下,实现对请求体的多次读取。这种方式既保证了拦截器的正常功能,又不会影响Controller层对请求体的解析。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

贝多芬也爱敲代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值