2011-06-12 75 views
8

我正在尝试为我的Web应用程序创建请求日志。我正在使用Spring 3. 0.记录HttpRequest参数和请求正文

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

在该方法中,我想能够登录请求主体(我的参数是直接写入请求主体的XML对象),并为我使用request.getReader();

的问题是 - 以后当弹簧控制器试图读取请求时,我会得到一个IllegalStateException

有没有办法做我想要的?

+0

有几个问题。在ServletRequest中,您只能调用getReader()或getInputStream()。如果你同时调用你会得到一个IllegalStateException。你可以尝试调用getInputStream,但是如果你阅读了输入流,你可能会得到一个错误,Spring可能无法看到它。 (ServletInputStream可能支持重置,但我不这么认为)。 你最好的选择是在XML反序列化过程中(你应该找出这个类是什么类)或者之后立即记录参数。 – Pace 2011-06-12 14:31:26

+0

您是否考虑过配置您的http服务器来记录请求头或使用servlet过滤器来执行日志记录? – happymeal 2011-06-12 14:42:15

+0

@happymeal我不需要头部我需要身体以及。 – 2011-06-12 14:43:12

回答

5

你可以用过滤器做到这一点。请求参数很容易处理。 但是处理请求主体将更加困难 并且需要包装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 
    } 

} 
+0

包装请求仍然不会让我调用'getReader()'两次。我仍然会收到illegalStateException – 2011-06-12 14:58:10

+0

Noam Nevo您将在原始请求上调用输入方法(reader/inputstream),然后使用getReader()和朋友重写的请求包装器封装原始请求。 – 2011-06-12 15:01:41

4

Spring有一个现成的过滤器来为你做的 - 看到this answer描述AbstractRequestLoggingFilter使用和它的子类。

请注意,使用此解决方案时,只有在请求处理完成并且应用程序已读取正文后才会记录请求正文。

+1

AbstractRequestLoggingFilter不允许您在请求处理之前记录请求。您无法在AbstractRequestLoggingFilter#beforeRequest中获取有效内容。如果可以的话,您可以重写AbstractRequestLoggingFilter#afterRequest,它将记录包括有效负载的所有内容。 – 2017-02-06 12:28:14

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