Java中使用HttpServletRequest读取请求体返回空字符串问题求助
这种情况我碰到过好多次,大概率是请求体被提前消耗了或者请求本身的问题,给你几个排查和解决的方向:
检查请求体是否被提前读取
Servlet的HttpServletRequest输入流和Reader是只能读取一次的!如果你的代码执行getReader()之前,已经有其他代码(比如框架的@RequestBody注解、getInputStream()调用,或者过滤器里的读取操作)把请求体读走了,那你再读就只能得到空字符串了。
解决办法是用HttpServletRequestWrapper缓存请求体,这样就能多次读取。下面给你贴一个缓存请求体的Wrapper示例,你可以在过滤器里先把请求包装成这个类,后面不管哪里读取都能拿到内容。确认请求的Content-Type是否匹配
如果你的请求是application/x-www-form-urlencoded类型的表单提交,Servlet容器会自动把参数解析到request.getParameterMap()里,这时候getReader()就读不到原始请求体了。这种情况要么用request.getParameter("参数名")获取值,要么如果一定要读原始请求体,就改成用multipart/form-data或者其他非表单类型的Content-Type,同时配合上面的Wrapper缓存。验证请求本身是否携带有效请求体
先确认你的请求方法是POST、PUT这类规范上允许携带请求体的方法(GET请求虽然HTTP规范没禁止,但大部分客户端和服务器都不支持携带请求体)。另外可以用抓包工具或者接口测试工具检查请求是否真的发送了请求体内容,避免是客户端没传导致的空值。检查读取代码的细节
虽然你的代码写法没大问题,但可以试试把System.lineSeparator()换成空字符串,有时候换行符的处理可能会有意外,但这个概率比较小。另外确保没有其他异常被吞掉,比如在读取前加个try-catch,看看有没有IO异常导致读取失败。
附上缓存请求体的工具类代码:
public class CachedBodyHttpServletRequestWrapper extends HttpServletRequestWrapper { private byte[] cachedBody; public CachedBodyHttpServletRequestWrapper(HttpServletRequest request) throws IOException { super(request); InputStream requestInputStream = request.getInputStream(); this.cachedBody = StreamUtils.copyToByteArray(requestInputStream); } @Override public ServletInputStream getInputStream() throws IOException { return new CachedServletInputStream(this.cachedBody); } @Override public BufferedReader getReader() throws IOException { ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(this.cachedBody); return new BufferedReader(new InputStreamReader(byteArrayInputStream)); } private static class CachedServletInputStream extends ServletInputStream { private final ByteArrayInputStream inputStream; public CachedServletInputStream(byte[] cachedBody) { this.inputStream = new ByteArrayInputStream(cachedBody); } @Override public int read() throws IOException { return this.inputStream.read(); } @Override public boolean isFinished() { return this.inputStream.available() == 0; } @Override public boolean isReady() { return true; } @Override public void setReadListener(ReadListener readListener) { throw new UnsupportedOperationException(); } } }
使用的时候,在过滤器里这样处理:
public class CachedBodyFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpServletRequest = (HttpServletRequest) request; CachedBodyHttpServletRequestWrapper wrappedRequest = new CachedBodyHttpServletRequestWrapper(httpServletRequest); chain.doFilter(wrappedRequest, response); } }
记得在web.xml或者用注解配置这个过滤器,让它在你需要读取请求体的代码之前执行。
内容的提问来源于stack exchange,提问作者Dilantha

