luk*_*ymo 24 java servlets servlet-filters
我想将记录添加到我的Servlet中,所以我创建了Filter,它应该显示请求并转到Servlet.但不幸的是我遇到了异常:
java.lang.IllegalStateException: getReader() has already been called for this request
at org.apache.catalina.connector.Request.getInputStream(Request.java:948)
at org.apache.catalina.connector.RequestFacade.getInputStream(RequestFacade.java:338)
at com.noelios.restlet.ext.servlet.ServletCall.getRequestEntityStream(ServletCall.java:190)
Run Code Online (Sandbox Code Playgroud)
所以为了解决这个问题,我找到了Wrapper的解决方案,但它不起作用.我还可以在代码中使用/更改什么?有任何想法吗?
[MyHttpServletRequestWrapper]
public class MyHttpServletRequestWrapper extends HttpServletRequestWrapper
{
public MyHttpServletRequestWrapper(HttpServletRequest request)
{
super(request);
}
private String getBodyAsString()
{
StringBuffer buff = new StringBuffer();
buff.append(" BODY_DATA START [ ");
char[] charArr = new char[getContentLength()];
try
{
BufferedReader reader = new BufferedReader(getReader());
reader.read(charArr, 0, charArr.length);
reader.close();
}
catch (IOException e)
{
e.printStackTrace();
}
buff.append(charArr);
buff.append(" ] BODY_DATA END ");
return buff.toString();
}
public String toString()
{
return getBodyAsString();
}
}
Run Code Online (Sandbox Code Playgroud)
[MyFilter]
public class MyFilterimplements Filter
{
@Override
public void init(FilterConfig filterConfig) throws ServletException
{
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
{
final HttpServletRequest httpServletRequest = (HttpServletRequest) request;
final HttpServletResponse httpServletResponse = (HttpServletResponse) response;
final HttpServletRequestWrapper requestWrapper = new MyHttpServletRequestWrapper(httpServletRequest);
final String requestBody = requestWrapper.toString();
chain.doFilter(request, response);
}
}
Run Code Online (Sandbox Code Playgroud)
Sur*_*mar 18
看起来restlet框架调用getRequestEntityStream()了Request对象,而该对象又调用getInputStream(),因此调用getReader()请求会抛出IllegalStateException.getReader()和getInputStream()的Servlet API文档说:
public java.io.BufferedReader getReader()
...
...
Throws:
java.lang.IllegalStateException - if getInputStream() method has been called on this request
public ServletInputStream getInputStream()
...
...
Throws:
java.lang.IllegalStateException - if the getReader() method has already been called for this request
Run Code Online (Sandbox Code Playgroud)
从文档中看来,我们无法在Request对象上同时调用getReader()和getInputStream().我建议你使用getInputStream()而不是getReader()在你的包装中.
使用ContentCachingRequestWrapper类。将 HttpServletRequest 包裹在这将解决问题
示例:如果你想转换你的“HttpServletRequest servletRequest”,你可以做一些类似的事情
import org.springframework.web.util.ContentCachingRequestWrapper;
ContentCachingRequestWrapper request = new ContentCachingRequestWrapper(servletRequest);
Run Code Online (Sandbox Code Playgroud)
希望能帮助到你!!!
据我所知,在这方面,servlet从根本上被破坏了。您可以尝试解决此处概述的此问题,但是当其他事情尝试使用它时,这会导致其他神秘的问题。
实际上,他建议克隆请求,读取正文,然后在克隆的类中重写getReader和getInputStream方法以返回已检索到的内容。
我最终得到的代码是这样的:
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
//this class stops reading the request payload twice causing an exception
public class WrappedRequest extends HttpServletRequestWrapper
{
private String _body;
private HttpServletRequest _request;
public WrappedRequest(HttpServletRequest request) throws IOException
{
super(request);
_request = request;
_body = "";
try (BufferedReader bufferedReader = request.getReader())
{
String line;
while ((line = bufferedReader.readLine()) != null)
_body += line;
}
}
@Override
public ServletInputStream getInputStream() throws IOException
{
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(_body.getBytes());
return new ServletInputStream()
{
public int read() throws IOException
{
return byteArrayInputStream.read();
}
};
}
@Override
public BufferedReader getReader() throws IOException
{
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
}
Run Code Online (Sandbox Code Playgroud)
无论如何,在我们意识到从浏览器上传文件无效之前,这似乎工作得很好。我将更改一分为二,发现这是罪魁祸首。
该文章中的评论中的某些人说,您需要重写方法来处理参数,但不解释如何执行此操作。
结果,我检查了两个请求是否有任何区别。但是,在克隆请求之后,它具有相同的参数集(原始请求+克隆的都没有参数)以及相同的标头集。
但是,以某种方式实现了请求,并且进一步加深了对请求的理解-在我的情况下,这导致库(extdirectspring)中出现一个bizaare错误,该库试图将内容读取为Json。取出在过滤器中读取正文的代码可使它再次工作。
我的调用代码如下所示:
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException
{
HttpServletRequest properRequest = ((HttpServletRequest)request);
String pathInfo = properRequest.getPathInfo();
String target = "";
if(pathInfo == null)
pathInfo = "";
if(pathInfo.equals("/router"))
{
//note this is because servlet requests hate you!
//if you read their contents more than once then they throw an exception so we need to do some madness
//to make this not the case
WrappedRequest wrappedRequest = new WrappedRequest(properRequest);
target = ParseExtDirectTargetFrom(wrappedRequest);
request = wrappedRequest;
}
boolean callingSpecialResetMethod = pathInfo.equals("/resetErrorState") || target.equals("resetErrorState");
if(_errorHandler.IsRejectingRequests() && !callingSpecialResetMethod)
return;
try {
filterChain.doFilter(request, response);
}
catch (Exception exception) {
((HttpServletResponse) response).sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "ERROR");
_errorHandler.NotifyOf(exception);
}
}
Run Code Online (Sandbox Code Playgroud)
我省略了内容,ParseExtDirectTargetFrom但调用了getReader()。
在我的情况下,过滤器正在处理所有其他请求,但这种情况下的奇怪行为使我意识到事情不太对劲,而我试图做的事情(对测试实施明智的异常处理行为)不值得破坏随机性。将来的请求(因为我不知道是什么导致了请求被破坏)。
同样值得注意的是,代码的破损是不可避免的-我认为这可能是从春天开始的,但是ServletRequest一直都在上升-即使您通过子类化HttpServlet从头开始制作servlet,也可以得到所有这些
我的建议是这样- 不要在过滤器中读取请求正文。您将打开一罐蠕虫,以后会引起奇怪的问题。
| 归档时间: |
|
| 查看次数: |
43284 次 |
| 最近记录: |