Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Logging HttpRequest parameters and request body

I am trying to create a request log for my web app. I am using Spring 3. 0.

I implemented a class extending HandlerInterceptorAdapter and used the preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) to intercept the request.

In the method i want to be able to log the request body (my parameters are objects in XML that are written directly to the request body), and for that i use request.getReader();

The problem is - later on I will get an IllegalStateException when the spring controller tries to read the request.

Is there a way to do what I intend?

like image 447
Noam Nevo Avatar asked Jun 12 '11 14:06

Noam Nevo


People also ask

How do you log HTTP request and response in spring boot?

Custom Request Logging Among the Spring request interceptors, one of the noteworthy interfaces is HandlerInterceptor, which we can use to log the incoming request by implementing the following methods: preHandle() – we execute this method before the actual controller service method.

How do you read request body multiple times spring?

Spring's ContentCachingRequestWrapper This class provides a method, getContentAsByteArray() to read the body multiple times. This class has a limitation, though: We can't read the body multiple times using the getInputStream() and getReader() methods. This class caches the request body by consuming the InputStream.

Can we send body GET request?

Requests using GET should only be used to request data (they shouldn't include data). Note: Sending body/payload in a GET request may cause some existing implementations to reject the request — while not prohibited by the specification, the semantics are undefined.

What is HttpServletRequestWrapper in Java?

HttpServletRequestWrapper(HttpServletRequest request) Constructs a request object wrapping the given request. Method Summary. boolean. authenticate(HttpServletResponse response)


2 Answers

Simple implementation for small requests. Don't use it for multipart request.

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();
        }
    }
}
like image 51
Eugene To Avatar answered Sep 22 '22 12:09

Eugene To


You can do this with a filter. The request parameters are easy to handle. However dealing with the request body will be much more difficult and will require wrapping the servlet request see: HttpServletRequest.

You will need to look how big the incoming request is and decide whether you want to store the request body as a tmp file or string.

You will need to override ServetRequest.getInputStream() with your file or saved string that used for logging.

If the request body is huge I recommend putting the input stream into a buffered input stream and then reading the start of the body.

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
    }

}
like image 44
Adam Gent Avatar answered Sep 20 '22 12:09

Adam Gent