读取一次后,Http Servlet请求从POST正文中丢失params

编程入门 行业动态 更新时间:2024-10-25 05:17:50
本文介绍了读取一次后,Http Servlet请求从POST正文中丢失params的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我正在尝试在Java Servlet过滤器中访问两个http请求参数,这里没什么新东西,但是很惊讶地发现参数已经被消耗了!因此,它在过滤器链中不再可用。

似乎只有当参数进入POST请求主体时才会出现这种情况(表单提交,对于例如)。

有没有办法读取参数而不消耗它们?

到目前为止我'我发现只有这个参考:使用request.getParameter的Servlet过滤器丢失表单数据。

谢谢!

另外,解决这个问题的另一种方法是不使用过滤器链而是构建自己的拦截器组件,可能使用可以在解析的请求体上操作的方面。它也可能更高效,因为您只需将请求 InputStream 转换为您自己的模型对象一次。

但是,我仍然认为想要多次读取请求主体是合理的,特别是当请求通过过滤器链时。我通常会使用过滤器链来处理某些我希望保留在HTTP层的操作,并与服务组件分离。

正如 Will Hartung 我通过扩展 HttpServletRequestWrapper 实现了这个目的,消耗了请求 InputStream 并且基本上缓存字节。

公共类MultiReadHttpServletRequest扩展HttpServletRequestWrapper { private ByteArrayOutputStream cachedBytes; public MultiReadHttpServletRequest(HttpServletRequest request){ super(request); } @Override public ServletInputStream getInputStream()抛出IOException { if(cachedBytes == null) cacheInputStream(); 返回新的CachedServletInputStream(); } @Override public BufferedReader getReader()抛出IOException {返回新的BufferedReader(new InputStreamReader(getInputStream())); } private void cacheInputStream()抛出IOException { / *缓存输入流以便多次读取它。对于 *方便,我使用apachemons IOUtils * / cachedBytes = new ByteArrayOutputStream(); IOUtils.copy(super.getInputStream(),cachedBytes); } / *一个读取缓存请求体的输入流* / 公共类CachedServletInputStream扩展了ServletInputStream { private ByteArrayInputStream输入; public CachedServletInputStream(){ / *从缓存的请求体创建一个新的输入流* / input = new ByteArrayInputStream(cachedBytes.toByteArray()); } @Override public int read()抛出IOException { return input.read(); } } }

现在请求正文可以是通过在传递过滤器链之前包装原始请求来多次读取:

public class MyFilter实现过滤器{ @Override public void doFilter(ServletRequest请求,ServletResponse响应, FilterChain链)抛出IOException,ServletException { / *包装请求以便多次读取输入流* / MultiReadHttpServletRequest multiReadRequest = new MultiReadHttpServletRequest((HttpServletRequest)request); / *这里我读了输入流并用它来做我的事情;当我通过过滤器链传递 *包装请求时,其余的过滤器和 *请求处理程序可以读取缓存的输入流 * / doMyThing(multiReadRequest.getInputStream ()); // OR anotherUsage(multiReadRequest.getReader()); chain.doFilter(multiReadRequest,response); } }

此解决方案还允许您阅读请求正文多次通过 getParameterXXX 方法,因为底层调用是 getInputStream(),这当然会读取缓存的请求 InputStream 。

I'm trying to accessing two http request parameters in a Java Servlet filter, nothing new here, but was surprised to find that the parameters have already been consumed! Because of this, it is not available anymore in the filter chain.

It seems that this only occurs when the parameters comes in a POST request body (a form submit, for example).

Is there a way to read the parameters and NOT consume them?

So far I've found only this reference: Servlet Filter using request.getParameter loses Form data.

Thanks!

解决方案

As an aside, an alternative way to solve this problem is to not use the filter chain and instead build your own interceptor component, perhaps using aspects, which can operate on the parsed request body. It will also likely be more efficient as you are only converting the request InputStream into your own model object once.

However, I still think it's reasonable to want to read the request body more than once particularly as the request moves through the filter chain. I would typically use filter chains for certain operations that I want to keep at the HTTP layer, decoupled from the service components.

As suggested by Will Hartung I achieved this by extending HttpServletRequestWrapper, consuming the request InputStream and essentially caching the bytes.

public class MultiReadHttpServletRequest extends HttpServletRequestWrapper { private ByteArrayOutputStream cachedBytes; public MultiReadHttpServletRequest(HttpServletRequest request) { super(request); } @Override public ServletInputStream getInputStream() throws IOException { if (cachedBytes == null) cacheInputStream(); return new CachedServletInputStream(); } @Override public BufferedReader getReader() throws IOException{ return new BufferedReader(new InputStreamReader(getInputStream())); } private void cacheInputStream() throws IOException { /* Cache the inputstream in order to read it multiple times. For * convenience, I use apachemons IOUtils */ cachedBytes = new ByteArrayOutputStream(); IOUtils.copy(super.getInputStream(), cachedBytes); } /* An inputstream which reads the cached request body */ public class CachedServletInputStream extends ServletInputStream { private ByteArrayInputStream input; public CachedServletInputStream() { /* create a new input stream from the cached request body */ input = new ByteArrayInputStream(cachedBytes.toByteArray()); } @Override public int read() throws IOException { return input.read(); } } }

Now the request body can be read more than once by wrapping the original request before passing it through the filter chain:

public class MyFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { /* wrap the request in order to read the inputstream multiple times */ MultiReadHttpServletRequest multiReadRequest = new MultiReadHttpServletRequest((HttpServletRequest) request); /* here I read the inputstream and do my thing with it; when I pass the * wrapped request through the filter chain, the rest of the filters, and * request handlers may read the cached inputstream */ doMyThing(multiReadRequest.getInputStream()); //OR anotherUsage(multiReadRequest.getReader()); chain.doFilter(multiReadRequest, response); } }

This solution will also allow you to read the request body multiple times via the getParameterXXX methods because the underlying call is getInputStream(), which will of course read the cached request InputStream.

更多推荐

读取一次后,Http Servlet请求从POST正文中丢失params

本文发布于:2023-10-09 18:41:24,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1476468.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:文中   Servlet   Http   params   POST

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!