2009-08-19 5 views
56

मैं अपने वेबपैड से लौटाए गए प्रत्येक HTTP स्टेटस कोड पर रिपोर्ट करने की कोशिश कर रहा हूं। हालांकि स्टेटस कोड ServletResponse के माध्यम से सुलभ प्रतीत नहीं होता है, या यहां तक ​​कि अगर मैं इसे HttpServletResponse में डाल देता हूं। ServletFilter के भीतर इस मान तक पहुंच प्राप्त करने का कोई तरीका है?मैं ServletFilter में ServletResponse से HTTP स्थिति कोड कैसे प्राप्त कर सकता हूं?

उत्तर

80

सबसे पहले, आपको स्थिति कोड को एक सुलभ स्थान पर सहेजने की आवश्यकता है। सबसे अच्छा आपके कार्यान्वयन के साथ प्रतिक्रिया लपेट और यह वहाँ रखने के लिए:

public class StatusExposingServletResponse extends HttpServletResponseWrapper { 

    private int httpStatus; 

    public StatusExposingServletResponse(HttpServletResponse response) { 
     super(response); 
    } 

    @Override 
    public void sendError(int sc) throws IOException { 
     httpStatus = sc; 
     super.sendError(sc); 
    } 

    @Override 
    public void sendError(int sc, String msg) throws IOException { 
     httpStatus = sc; 
     super.sendError(sc, msg); 
    } 


    @Override 
    public void setStatus(int sc) { 
     httpStatus = sc; 
     super.setStatus(sc); 
    } 

    public int getStatus() { 
     return httpStatus; 
    } 

} 

आदेश में इस आवरण का उपयोग करने के लिए, आप एक सर्वलेट फ़िल्टर जोड़ने के लिए की जरूरत है, थे आपने अपने रिपोर्टिंग कर सकते हैं:

public class StatusReportingFilter implements Filter { 

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { 
     StatusExposingServletResponse response = new StatusExposingServletResponse((HttpServletResponse)res); 
     chain.doFilter(req, response); 
     int status = response.getStatus(); 
     // report 
    } 

    public void init(FilterConfig config) throws ServletException { 
     //empty 
    } 

    public void destroy() { 
     // empty 
    } 

} 
+8

मामले में कोई पृष्ठ के अंत तक नहीं पढ़ता है, जोएल की टिप्पणी को डिफ़ॉल्ट स्थिति = 200 भी सेट करने के लिए नीचे देखें और प्रेषण को ओवरराइड करने के लिए (..) –

+1

यह टोमकैट के पुराने संस्करण के लिए बेहद सहायक था जो सर्वलेट spec 2.4 पर है। धन्यवाद! – user3621633

+0

respond.sendRedirect() अवैधStateExcpetion दे रहा है। मैंने जोएल की टिप्पणी –

6

एक HttpServletResponseWrapper लिखें और सभी सेटस्टैटस(), sendError(), और sendRedirect() विधियों को सब कुछ लॉग इन करने के लिए ओवरराइड करें। एक फ़िल्टर लिखें जो प्रत्येक अनुरोध पर प्रतिक्रिया ऑब्जेक्ट के लिए आपके रैपर को स्वैप करता है।

11

@Override 
public void sendError(int sc, String msg) throws IOException { 
    httpStatus = sc; 
    super.sendError(sc, msg); 
} 
+0

धन्यवाद विलियम, मैंने इसे जोड़ा है मेरे नमूने के लिए। –

59

सर्वलेट 3.0 के बाद से, वहाँ एक HttpServletResponse#getStatus(): एक बात ऊपर डेविड के जवाब से लापता है कि आप भी sendError के अन्य रूप ओवरराइड करना चाहिए है।

तो, यदि अपग्रेड करने के लिए कोई कमरा है, तो सर्वलेट 3.0 (टॉमकैट 7, ग्लासफ़िश 3, जेबॉस एएस 6 इत्यादि) में अपग्रेड करें और आपको एक रैपर की आवश्यकता नहीं है।

chain.doFilter(request, response); 
int status = ((HttpServletResponse) response).getStatus(); 
+0

यह अच्छा है। धन्यवाद महोदय! – asgs

+0

टोमकैट 6 के बारे में क्या ?? सर्वलेट संस्करण 3 –

+0

@ सैम से नीचे है: यह प्रश्न का एकमात्र उत्तर नहीं है। वर्तमान में स्वीकृत उत्तर इतना पुराना है कि यह अभी भी टॉमकैट 6 पर लागू होता है। – BalusC

14

इसके अलावा #sendRedirect के लिए एक आवरण शामिल करने की जरूरत है, और यह बेहतर होगा '200' के बजाय '0'

private int httpStatus = SC_OK; 

... 

@Override 
public void sendRedirect(String location) throws IOException { 
    httpStatus = SC_MOVED_TEMPORARILY; 
    super.sendRedirect(location); 
} 
+0

मैं उन परिस्थितियों को देख सकता हूं जहां आपका फ़िल्टर मैपिंग प्लेसमेंट प्रभावित हो सकता है कि आपका ओवरराइडिंग कोड ट्रिगर हो गया है या नहीं। उदाहरण के लिए, एक सतत फ़िल्टर आपकी प्रतिक्रिया को लपेट नहीं सकता है बल्कि इसे प्रतिस्थापित कर सकता है। उन परिदृश्यों के अलावा, स्थिति कोड को सेटस्टैटस, sendError या sendRedirect वेरिएंट के बिना प्रतिक्रिया पर सेट किया जा सकता है? क्या आपने 200 से स्थिति शुरू की है? – 1in9ui5t

0

स्थिति प्रारंभ करने में आप तो एक पुराने कंटेनर के साथ फंस रहे हैं, तो डेविड Rabinowitz करने के लिए एक वैकल्पिक समाधान वास्तविक स्थिति कोड का उपयोग करता है (के बाद यह आवरण का उपयोग कर सेट किया गया है यह परिवर्तन मामले में) है:

public class StatusExposingServletResponse extends HttpServletResponseWrapper { 

    public StatusExposingServletResponse(HttpServletResponse response) { 
     super(response); 
    } 

    @Override 
    public void sendError(int sc) throws IOException { 
     super.sendError(sc); 
    } 

    @Override 
    public void sendError(int sc, String msg) throws IOException { 
     super.sendError(sc, msg); 
    } 

    @Override 
    public void setStatus(int sc) { 
     super.setStatus(sc); 
    } 

    public int getStatus() { 
     try { 
      ServletResponse object = super.getResponse(); 

      // call the private method 'getResponse' 
      Method method1 = object.getClass().getMethod("getResponse"); 
      Object servletResponse = method1.invoke(object, new Object[] {}); 

      // call the parents private method 'getResponse' 
      Method method2 = servletResponse.getClass().getMethod("getResponse"); 
      Object parentResponse = method2.invoke(servletResponse, new Object[] {}); 

      // call the parents private method 'getResponse' 
      Method method3 = parentResponse.getClass().getMethod("getStatus"); 
      int httpStatus = (Integer) method3.invoke(parentResponse, new Object[] {}); 

      return httpStatus; 
     } 
     catch (Exception e) { 
      e.printStackTrace(); 
      return HttpServletResponse.SC_ACCEPTED; 
     } 
    } 

    public String getMessage() { 
     try { 
      ServletResponse object = super.getResponse(); 

      // call the private method 'getResponse' 
      Method method1 = object.getClass().getMethod("getResponse"); 
      Object servletResponse = method1.invoke(object, new Object[] {}); 

      // call the parents private method 'getResponse' 
      Method method2 = servletResponse.getClass().getMethod("getResponse"); 
      Object parentResponse = method2.invoke(servletResponse, new Object[] {}); 

      // call the parents private method 'getResponse' 
      Method method3 = parentResponse.getClass().getMethod("getReason"); 
      String httpStatusMessage = (String) method3.invoke(parentResponse, new Object[] {}); 

      if (httpStatusMessage == null) { 
       int status = getStatus(); 
       java.lang.reflect.Field[] fields = HttpServletResponse.class.getFields(); 

       for (java.lang.reflect.Field field : fields) { 
        if (status == field.getInt(servletResponse)) { 
         httpStatusMessage = field.getName(); 
         httpStatusMessage = httpStatusMessage.replace("SC_", ""); 
         if (!"OK".equals(httpStatusMessage)) { 
          httpStatusMessage = httpStatusMessage.toLowerCase(); 
          httpStatusMessage = httpStatusMessage.replace("_", " "); 
          httpStatusMessage = capitalizeFirstLetters(httpStatusMessage); 
         } 

         break; 
        } 
       } 
      } 

      return httpStatusMessage; 
     } 
     catch (Exception e) { 
      e.printStackTrace(); 
      return ""; 
     } 
    } 

    private static String capitalizeFirstLetters(String s) { 

     for (int i = 0; i < s.length(); i++) { 
      if (i == 0) { 
       // Capitalize the first letter of the string. 
       s = String.format("%s%s", Character.toUpperCase(s.charAt(0)), s.substring(1)); 
      } 

      if (!Character.isLetterOrDigit(s.charAt(i))) { 
       if (i + 1 < s.length()) { 
        s = String.format("%s%s%s", s.subSequence(0, i + 1), 
          Character.toUpperCase(s.charAt(i + 1)), 
          s.substring(i + 2)); 
       } 
      } 
     } 

     return s; 

    } 

    @Override 
    public String toString() { 
     return this.getMessage() + " " + this.getStatus(); 
    } 

} 

चेतावनी: वर्ग पदानुक्रम की मान्यताओं के बहुत सारे जब sne का उपयोग कर निजी डेटा मूल्यों को प्राप्त करने के लिए अजीब प्रतिबिंब और आत्मनिरीक्षण।

6

डेविड का जवाब देने के लिए इसके अलावा, आप भी रीसेट करने की विधि ओवरराइड करने के लिए चाहता हूँ:

@Override 
public void reset() { 
    super.reset(); 
    this.httpStatus = SC_OK; 
} 

... और साथ ही पदावनत setStatus (पूर्णांक, स्ट्रिंग)

@Override 
public void setStatus(int status, String string) { 
    super.setStatus(status, string); 
    this.httpStatus = status; 
} 
संबंधित मुद्दे