2011-06-12 69 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(); 
     } 
    } 
}