2010-07-13 12 views
19

मेरे पास एक सर्वलेट है जो कुछ HTTP अनुरोधों और प्रतिक्रियाओं को संभालता है। मैं ग्राहक को वापस भेजने से पहले प्रतिक्रिया निकाय को लॉग करना चाहता हूं। क्या कोई तरीका है कि मैं प्रतिक्रिया शरीर को HttpServletResponse ऑब्जेक्ट से सर्वलेट से भेजने से पहले कैप्चर कर सकता हूं?प्रतिक्रिया शरीर को कैप्चर और लॉग करें

उत्तर

25

यदि मैं आपको सही ढंग से समझता हूं, तो आप प्रतिक्रिया शरीर पर लॉग इन करना चाहते हैं? यह एक बहुत महंगा काम है, लेकिन यदि यह व्यवसाय की आवश्यकता है ...

@duffymo ने बताया, Filter इसके लिए उपयुक्त स्थान है। आप को HttpServletResponseWrapper कार्यान्वयन के साथ HttpServletResponse#getWriter() को अपने कार्यान्वयन के साथ बदलकर प्रतिक्रिया शरीर को कैप्चर कर सकते हैं जो कुछ बफर में प्रतिक्रिया निकाय की प्रतिलिपि बनाता है। प्रतिस्थापित प्रतिक्रिया के साथ फ़िल्टर श्रृंखला जारी रखने के बाद, बस प्रतिलिपि लॉग करें।

यहाँ एक किकऑफ़ उदाहरण है की तरह doFilter() विधि देख सकते हैं कैसे:

public class CopyPrintWriter extends PrintWriter { 

    private StringBuilder copy = new StringBuilder(); 

    public CopyPrintWriter(Writer writer) { 
     super(writer); 
    } 

    @Override 
    public void write(int c) { 
     copy.append((char) c); // It is actually a char, not an int. 
     super.write(c); 
    } 

    @Override 
    public void write(char[] chars, int offset, int length) { 
     copy.append(chars, offset, length); 
     super.write(chars, offset, length); 
    } 

    @Override 
    public void write(String string, int offset, int length) { 
     copy.append(string, offset, length); 
     super.write(string, offset, length); 
    } 

    public String getCopy() { 
     return copy.toString(); 
    } 

} 

मानचित्र एक url-pattern पर इस फिल्टर जिसके लिए आप चाहते हैं:

public void doFilter(ServletRequest request, final ServletResponse response, FilterChain chain) throws IOException, ServletException { 
    final CopyPrintWriter writer = new CopyPrintWriter(response.getWriter()); 
    chain.doFilter(request, new HttpServletResponseWrapper((HttpServletResponse) response) { 
     @Override public PrintWriter getWriter() { 
      return writer; 
     } 
    }); 
    logger.log(writer.getCopy()); 
} 

यहाँ CopyPrintWriter की तरह लग रही है कि कैसे कर सकते हैं के लिए प्रतिक्रिया लॉग इन करने के लिए। ध्यान रखें कि छवियों, सीएसएस, जेएस फाइलों जैसी बाइनरी/स्थैतिक सामग्री इस तरह से लॉग इन नहीं की जाएगी। आप उन्हें एक विशिष्ट पर्याप्त url-pattern का उपयोग कर बहिष्कृत करना चाहते हैं, उदा। प्रश्न में सर्वलेट के *.jsp या बस servlet-name पर। यदि आप बाइनरी/स्थैतिक सामग्री को वैसे भी लॉग करना चाहते हैं (जिसके लिए मुझे कोई लाभ नहीं दिखाई देता है), तो आपको HttpServletResponse#getOutputStream() को उसी तरह से बदलना होगा।

+0

की प्रतिलिपि बनाने के संकेत को याद करता है आपको केवल ओवरराइड नहीं करना चाहिए 'getWriter()', लेकिन 'getOutputStream() ' – pihentagy

+0

समस्याओं को एन्कोड करने के बारे में कैसे? – pihentagy

+0

@pihentagy: 1) यदि आपको आवश्यकता है। 2) 'setCharacterEncoding()' विधि द्वारा सेट किया गया वही उपयोग करें। – BalusC

4

शायद servlet filter आपकी मदद कर सकता है। इसके बारे में HTTP के लिए पहलू उन्मुख प्रोग्रामिंग के रूप में सोचें।

+2

मजेदार कैसे अन्य सभी उत्तर मेरा उद्धरण देते हैं, लेकिन यह स्वीकार्य नहीं था .... – duffymo

+6

यह वास्तव में एक सहायक संकेत था (ऊपर की ओर), लेकिन 'प्रिंटवाइटर' – pihentagy

3

BalusC answer का विकल्प वैकल्पिक रूप से दो आउटपुटस्ट्रीम में लिखने के लिए TeeutputStream का उपयोग करना।

public void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws IOException, ServletException { 
    ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
    final PrintStream ps = new PrintStream(baos); 

    chain.doFilter(req,new HttpServletResponseWrapper(res) { 
     @Override 
     public ServletOutputStream getOutputStream() throws IOException { 
      return new DelegatingServletOutputStream(new TeeOutputStream(super.getOutputStream(), ps) 
      ); 
     } 
     @Override 
     public PrintWriter getWriter() throws IOException { 
      return new PrintWriter(new DelegatingServletOutputStream (new TeeOutputStream(super.getOutputStream(), ps)) 
      ); 
     } 
     }); 

    //Get Response body calling baos.toString(); 
} 
+1

भविष्य की पीढ़ियों के लाभ के लिए ... कौन सी लाइब्रेरी 'टीओयूटपुटस्ट्रीम' और 'डिलीगेटिंग सर्लेटऑटपुटस्ट्रीम' हैं? –

+0

यह वसंत और अपाचे io से है। 1) https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/mock/web/DelegatingServletOutputStream.html 2) https://commons.apache.org/proper/commons-io /javadocs/api-1.4/org/apache/commons/io/output/TeeOutputStream.html – Happier

-1

मैं तृतीय पक्ष निर्भरता के बिना आउटपुटस्ट्रीम संस्करण बना देता हूं, जो @pdorgambide के समान है। आप this link में पा सकते हैं।

+0

केवल लिंक ही लिंक खराब हैं ... लिंक अंततः टूट जाते हैं। – Gus

+0

क्या आप यह प्रश्न खोल सकते हैं? http://stackoverflow.com/questions/10457963/spring-rest-service-retrieving-json-from-request/29005111#29005111 – Happier

संबंधित मुद्दे