我正在尝试为我的网络应用创建请求日志。我正在使用Spring 3。 0
我实施了一个扩展HandlerInterceptorAdapter
的类,并使用preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
来拦截请求。
在方法中,我希望能够记录请求体(我的参数是XML中直接写入请求体的对象),为此我使用request.getReader();
问题是 - 稍后我会在弹簧控制器尝试读取请求时得到IllegalStateException
。
有办法做我想做的事吗?
答案 0 :(得分:6)
您可以使用过滤器执行此操作。请求参数易于处理。 但是,处理请求机构将会困难得多 并且需要包装servlet请求,请参阅:HttpServletRequest。
您需要查看传入请求的大小,并决定是否要将请求正文存储为tmp文件或字符串。
您需要使用您的文件或用于记录的已保存字符串覆盖ServetRequest.getInputStream()。
如果请求体很大,我建议将输入流放入缓冲的输入流中,然后读取正文的开头。
public class LogRequest extends HttpServletRequestWrapper {
public LogRequest(HttpServletRequest request) {
super(request);
}
@Override
public ServletInputStream getInputStream() throws IOException {
//read from tmp file or string.
}
@Override
public BufferedReader getReader() throws IOException {
//read from tmp file or string
}
}
答案 1 :(得分:4)
Spring有一个现成的过滤器可以帮助您完成此操作 - 请参阅AbstractRequestLoggingFilter
中描述的{{1}}及其子类的用法。
请注意,使用此解决方案时,只有在请求处理完成且应用程序已读取正文后才会记录请求正文。
答案 2 :(得分:0)
小请求的简单实现。不要将它用于多部分请求。
package ru.rbs.logger.web;
import org.apache.commons.io.IOUtils;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
class CachedRequestWrapper extends HttpServletRequestWrapper {
private final byte[] cachedBody;
CachedRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
IOUtils.copy(request.getInputStream(), bos);
cachedBody = bos.toByteArray();
}
@Override
public ServletInputStream getInputStream() throws IOException {
return new CachedServletInputStream();
}
byte[] toByteArray(){
return cachedBody;
}
private class CachedServletInputStream extends ServletInputStream {
private InputStream baseInputStream;
CachedServletInputStream() throws IOException {
baseInputStream = new ByteArrayInputStream(cachedBody);
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
@Override
public int read() throws IOException {
return baseInputStream.read();
}
}
}