2011-09-06 10 views
14

मैं अपने सर्वलेट में लॉगिंग जोड़ना चाहता हूं, इसलिए मैंने फ़िल्टर बनाया है जो अनुरोध प्रदर्शित करना चाहिए और सर्वलेट पर जाना चाहिए।java.lang.IllegalStateException: getReader() को पहले से ही इस अनुरोध के लिए बुलाया गया है

java.lang.IllegalStateException: getReader() has already been called for this request 
    at org.apache.catalina.connector.Request.getInputStream(Request.java:948) 
    at org.apache.catalina.connector.RequestFacade.getInputStream(RequestFacade.java:338) 
    at com.noelios.restlet.ext.servlet.ServletCall.getRequestEntityStream(ServletCall.java:190) 

तो इस समस्या को मैं आवरण के साथ समाधान मिल गया है ठीक करने के लिए है, लेकिन यह काम नहीं करता है: लेकिन दुर्भाग्य से मैं encoutered अपवाद है। मैं कोड में और क्या उपयोग कर सकता/सकती हूं? कोई विचार?

[MyHttpServletRequestWrapper]

public class MyHttpServletRequestWrapper extends HttpServletRequestWrapper 
{ 
    public MyHttpServletRequestWrapper(HttpServletRequest request) 
    { 
     super(request); 
    } 

    private String getBodyAsString() 
    { 
     StringBuffer buff = new StringBuffer(); 
     buff.append(" BODY_DATA START [ "); 
     char[] charArr = new char[getContentLength()]; 
     try 
     { 
      BufferedReader reader = new BufferedReader(getReader()); 
      reader.read(charArr, 0, charArr.length); 
      reader.close(); 
     } 
     catch (IOException e) 
     { 
      e.printStackTrace(); 
     } 
     buff.append(charArr); 
     buff.append(" ] BODY_DATA END "); 
     return buff.toString(); 
    } 

    public String toString() 
    { 
     return getBodyAsString(); 
    } 
} 

[MyFilter]

public class MyFilterimplements Filter 
{ 
    @Override 
    public void init(FilterConfig filterConfig) throws ServletException 
    { 
    } 

    @Override 
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException 
    { 
     final HttpServletRequest httpServletRequest = (HttpServletRequest) request; 
     final HttpServletResponse httpServletResponse = (HttpServletResponse) response; 

     final HttpServletRequestWrapper requestWrapper = new MyHttpServletRequestWrapper(httpServletRequest); 
     final String requestBody = requestWrapper.toString(); 

     chain.doFilter(request, response); 
    } 
} 

उत्तर

9

लगता restlet ढांचे की तरह getRequestEntityStream() अनुरोध वस्तु है जो बदले में कॉल getInputStream() से कहा है, तो बुला अनुरोध पर getReader()IllegalStateException फेंकता । getReader() और getInputStream() के लिए सर्वलेट API दस्तावेज़ का कहना है:

public java.io.BufferedReader getReader() 
    ... 
    ... 
Throws: 
    java.lang.IllegalStateException - if getInputStream() method has been called on this request 

public ServletInputStream getInputStream() 
    ... 
    ... 
    Throws: 
    java.lang.IllegalStateException - if the getReader() method has already been called for this request 

प्रलेखन से ऐसा लगता है कि हम अनुरोध वस्तु पर दोनों getReader() और getInputStream() फोन नहीं कर सकते हैं। मेरा सुझाव है कि आप अपने रैपर में getReader() के बजाय getInputStream() का उपयोग करें।

5

मुख्य समस्या यह है कि आप दोनों को बाइनरी स्ट्रीम और कैरेक्टर स्ट्रीम के रूप में इनपुट नहीं पढ़ सकते हैं, भले ही किसी को फ़िल्टर में नहीं कहा जाता है और दूसरा सर्वलेट में भी कहा जाता है।

3

जहां तक ​​मैं कह सकता हूं कि सर्वलेट मूल रूप से इस संबंध में टूटे हैं। आप here रूपरेखा के रूप में इस समस्या को हल करने और काम करने के लिए कोशिश कर सकते हैं, लेकिन इससे अन्य रहस्यमय समस्याएं होती हैं जब अन्य चीजें इसके साथ प्रयास करती हैं और काम करती हैं।

प्रभावी रूप से वह अनुरोध को क्लोन करने, शरीर को पढ़ने और उसके बाद क्लोन क्लास में getReader को ओवरराइड करने और getInputStream विधियों को पहले से पुनर्प्राप्त सामग्री को वापस करने का सुझाव देता है।

import javax.servlet.ServletInputStream; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletRequestWrapper; 
import java.io.*; 

//this class stops reading the request payload twice causing an exception 
public class WrappedRequest extends HttpServletRequestWrapper 
{ 
    private String _body; 
    private HttpServletRequest _request; 

    public WrappedRequest(HttpServletRequest request) throws IOException 
    { 
     super(request); 
     _request = request; 

     _body = ""; 
     try (BufferedReader bufferedReader = request.getReader()) 
     { 
      String line; 
      while ((line = bufferedReader.readLine()) != null) 
       _body += line; 
     } 
    } 

    @Override 
    public ServletInputStream getInputStream() throws IOException 
    { 
     final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(_body.getBytes()); 
     return new ServletInputStream() 
     { 
      public int read() throws IOException 
      { 
       return byteArrayInputStream.read(); 
      } 
     }; 
    } 

    @Override 
    public BufferedReader getReader() throws IOException 
    { 
     return new BufferedReader(new InputStreamReader(this.getInputStream())); 
    } 
} 

इस ठीक काम कर रहा होना को दिखाई, जब तक हम महसूस किया कि ब्राउज़र से एक फ़ाइल को अपलोड करने से काम नहीं कर रहा था वैसे भी:

कोड मैं साथ समाप्त हो गया इस था। मैंने परिवर्तनों के माध्यम से विभाजित किया और पाया कि यह अपराधी था।

उस आलेख में टिप्पणियों में से कुछ लोग कहते हैं कि आपको पैरामीटर के साथ करने के तरीकों को ओवरराइड करने की आवश्यकता है लेकिन यह समझाने के लिए कि यह कैसे करें।

परिणामस्वरूप मैंने यह देखने के लिए जांच की कि क्या दो अनुरोधों में कोई अंतर है या नहीं। हालांकि अनुरोध को क्लोन करने के बाद इसमें पैरामीटर के समान सेट थे (मूल अनुरोध + क्लोन दोनों में कोई नहीं था) साथ ही हेडर के समान सेट के रूप में।

हालांकि किसी भी तरीके से अनुरोध को प्रभावित किया जा रहा था और लाइन के नीचे अनुरोध की समझ को खराब कर रहा था - मेरे मामले में लाइब्रेरी में एक विचित्र त्रुटि उत्पन्न हुई (जहां extdirectspring) जहां कुछ जेसन के रूप में सामग्री को पढ़ने की कोशिश कर रहा था। फिल्टर में शरीर को पढ़ने वाले कोड को फिर से काम करना।

मेरे बुला कोड इस तरह देखा:

@Override 
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException 
{ 
    HttpServletRequest properRequest = ((HttpServletRequest)request); 

    String pathInfo = properRequest.getPathInfo(); 
    String target = ""; 
    if(pathInfo == null) 
     pathInfo = ""; 

    if(pathInfo.equals("/router")) 
    { 
     //note this is because servlet requests hate you! 
     //if you read their contents more than once then they throw an exception so we need to do some madness 
     //to make this not the case 
     WrappedRequest wrappedRequest = new WrappedRequest(properRequest); 
     target = ParseExtDirectTargetFrom(wrappedRequest); 
     request = wrappedRequest; 
    } 

    boolean callingSpecialResetMethod = pathInfo.equals("/resetErrorState") || target.equals("resetErrorState"); 
    if(_errorHandler.IsRejectingRequests() && !callingSpecialResetMethod) 
     return; 

    try { 
     filterChain.doFilter(request, response); 
    } 
    catch (Exception exception) { 
     ((HttpServletResponse) response).sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "ERROR"); 
     _errorHandler.NotifyOf(exception); 
    } 
} 

मैं ParseExtDirectTargetFrom की सामग्री को लोप है, लेकिन यह getReader() कहते हैं।

मेरे मामले में फ़िल्टर अन्य सभी अनुरोधों के लिए काम कर रहा था लेकिन इस मामले में अजीब व्यवहार ने मुझे महसूस किया कि कुछ सही नहीं था और मैं क्या करने की कोशिश कर रहा था (परीक्षण के लिए समझदार अपवाद हैंडलिंग व्यवहार लागू नहीं किया गया था) संभावित रूप से यादृच्छिक भविष्य के अनुरोधों को तोड़ने के लायक (जैसा कि मुझे पता नहीं लगा कि अनुरोध टूटा हुआ था)।

यह भी ध्यान देने योग्य बात है कि टूटे हुए कोड अपरिहार्य है लायक है - मैं इसे वसंत से कुछ हो सकता है ग्रहण किया लेकिन ServletRequest नीचे से ऊपर तक चला जाता है - आप सभी, भले ही आप स्क्रैच से एक सर्वलेट बना रहे थे मिल thats HttpServlet

उपवर्गीकरण द्वारा

मेरी सिफारिश यह होगी - फ़िल्टर में अनुरोध निकाय को न पढ़ें। आप कीड़े का एक खोल खोलेंगे जो बाद में अजीब समस्याओं का कारण बन जाएगा।

0

सामग्री कैशिंगआरक्वैस्टवापर कक्षा का उपयोग करें। थाई में HttpServletRequest समस्या

हल करेगा
संबंधित मुद्दे