记录HttpRequest参数和请求正文

时间:2011-06-12 14:03:32

标签: java spring-mvc httprequest

我正在尝试为我的网络应用创建请求日志。我正在使用Spring 3。 0

我实施了一个扩展HandlerInterceptorAdapter的类,并使用preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)来拦截请求。

在方法中,我希望能够记录请求体(我的参数是XML中直接写入请求体的对象),为此我使用request.getReader();

问题是 - 稍后我会在弹簧控制器尝试读取请求时得到IllegalStateException

有办法做我想做的事吗?

3 个答案:

答案 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();
        }
    }
}