2010-12-15 13 views
26

मैं इस कोड है:कैसे request.getInputStream पढ़ने के लिए() कई बार

@Override 
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
     throws IOException, ServletException { 
    logger.info("Filter start..."); 

    HttpServletRequest httpRequest = (HttpServletRequest) request; 
    HttpServletResponse httpResponse = (HttpServletResponse) response; 

    String ba = getBaId(getBody(httpRequest)); 

    if (ba == null) { 
     logger.error("Wrong XML"); 
     httpResponse.setStatus(HttpServletResponse.SC_BAD_REQUEST); 
    } else {  

     if (!clients.containsKey(ba)) { 
      clients.put(ba, 1); 
      logger.info("Client map : init..."); 
     } else { 
      clients.put(ba, clients.get(ba).intValue() + 1); 
      logger.info("Threads for " + ba + " = " + clients.get(ba).toString()); 
     } 

     chain.doFilter(request, response); 
    } 
} 

और इस web.xml (संकुल छोटा कर रहे हैं और नाम बदल, लेकिन यह एक ही लग रहा है)

<?xml version="1.0" encoding="ISO-8859-1"?> 
<web-app> 
    <filter> 
    <filter-name>TestFilter</filter-name> 
    <filter-class>pkg.TestFilter</filter-class> 
    </filter> 
    <filter-mapping> 
    <filter-name>TestFilter</filter-name> 
    <url-pattern>/*</url-pattern> 
    </filter-mapping> 

    <context-param> 
    <param-name>contextConfigLocation</param-name> 
    <param-value>WEB-INF/applicationContext.xml</param-value> 
    </context-param> 

    <listener> 
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 
    </listener> 

    <servlet> 
    <servlet-name>Name</servlet-name> 
    <display-name>Name</display-name> 
    <servlet-class>pkg.Name</servlet-class> 
    <load-on-startup>1</load-on-startup> 
    </servlet> 
    <servlet-mapping> 
    <servlet-name>Name</servlet-name> 
    <url-pattern>/services/*</url-pattern> 
    </servlet-mapping> 
</web-app> 

मैं फ़िल्टर के बाद सर्वलेट को आमंत्रित करना चाहता हूं। मैं chain.doFilter(...) उम्मीद थी चाल कर सकता है, लेकिन मैं हमेशा chain.doFilter(...) के साथ लाइन पर इस त्रुटि मिलती है:

java.lang.IllegalStateException: getInputStream() can't be called after getReader() 
at com.caucho.server.connection.AbstractHttpRequest.getInputStream(AbstractHttpRequest.java:1933) 
at org.apache.cxf.transport.http.AbstractHTTPDestination.setupMessage(AbstractHTTPDestination.java:249) 
at org.apache.cxf.transport.servlet.ServletDestination.invoke(ServletDestination.java:82) 
at org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:283) 
at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:166) 
at org.apache.cxf.transport.servlet.AbstractCXFServlet.invoke(AbstractCXFServlet.java:174) 
at org.apache.cxf.transport.servlet.AbstractCXFServlet.doPost(AbstractCXFServlet.java:152) 
at javax.servlet.http.HttpServlet.service(HttpServlet.java:153) 
at javax.servlet.http.HttpServlet.service(HttpServlet.java:91) 
at com.caucho.server.dispatch.ServletFilterChain.doFilter(ServletFilterChain.java:103) 
at pkg.TestFilter.doFilter(TestFilter.java:102) 
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:87) 
at com.caucho.server.webapp.WebAppFilterChain.doFilter(WebAppFilterChain.java:187) 
at com.caucho.server.dispatch.ServletInvocation.service(ServletInvocation.java:265) 
at com.caucho.server.http.HttpRequest.handleRequest(HttpRequest.java:273) 
at com.caucho.server.port.TcpConnection.run(TcpConnection.java:682) 
at com.caucho.util.ThreadPool$Item.runTasks(ThreadPool.java:743) 
at com.caucho.util.ThreadPool$Item.run(ThreadPool.java:662) 
at java.lang.Thread.run(Thread.java:619) 
+0

हां, यह काम करना चाहिए। क्या servlet फिल्टर के बिना काम करता है? – morja

+0

सर्वलेट फिल्टर के बिना काम करता है और 'chain.doFilter()' के बिना फ़िल्टर भी – user219882

+0

इसे बाहर रखता है ..अन्यथा – user219882

उत्तर

7

आप शायद लेने शुरू HttpServletRequest में getReader() का उपयोग कर:

String ba = getBaId(getBody(httpRequest)); 

आपका सर्वलेट कॉल करने के लिए कोशिश करता है उसी अनुरोध पर getInputStream(), जिसकी अनुमति नहीं है। अनुरोध के शरीर की एक प्रति बनाने के लिए आपको क्या करना है ServletRequestWrapper का उपयोग करना है, ताकि आप इसे कई तरीकों से पढ़ सकें। मेरे पास एक पूर्ण उदाहरण खोजने का समय नहीं है ... माफ करना ...

+2

अनुरोध की एक प्रति रखने और 'getReader()' का उपयोग करने से मदद नहीं मिलती है। अपवाद होगा 'getReader() को पहले से ही इस अनुरोध के लिए बुलाया गया है –

6

स्वीकार्य उत्तर के आधार पर कार्य कोड। सर्वलेट अनुरोध में

public class CustomHttpServletRequestWrapper extends HttpServletRequestWrapper { 

private static final Logger logger = Logger.getLogger(CustomHttpServletRequestWrapper.class); 
private final String body; 

public CustomHttpServletRequestWrapper(HttpServletRequest request) { 
    super(request); 

    StringBuilder stringBuilder = new StringBuilder(); 
    BufferedReader bufferedReader = null; 

    try { 
     InputStream inputStream = request.getInputStream(); 

     if (inputStream != null) { 
      bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); 

      char[] charBuffer = new char[128]; 
      int bytesRead = -1; 

      while ((bytesRead = bufferedReader.read(charBuffer)) > 0) { 
       stringBuilder.append(charBuffer, 0, bytesRead); 
      } 
     } else { 
      stringBuilder.append(""); 
     } 
    } catch (IOException ex) { 
     logger.error("Error reading the request body..."); 
    } finally { 
     if (bufferedReader != null) { 
      try { 
       bufferedReader.close(); 
      } catch (IOException ex) { 
       logger.error("Error closing bufferedReader..."); 
      } 
     } 
    } 

    body = stringBuilder.toString(); 
} 

@Override 
public ServletInputStream getInputStream() throws IOException {   
    final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes()); 

    ServletInputStream inputStream = new ServletInputStream() { 
     public int read() throws IOException { 
      return byteArrayInputStream.read(); 
     } 
    }; 

    return inputStream; 
} 
} 
1

InputStream केवल इसकी वजह से एक बार इस्तेमाल किया जा सकता धारा है, तो आप इसे स्टोर और फिर एक बाइट सरणी से प्राप्त कर सकते हैं, इस को हल कर सकते हैं।

public class HttpServletRequestWrapper extends javax.servlet.http.HttpServletRequestWrapper { 

private final byte[] body; 

public HttpServletRequestWrapper(HttpServletRequest request) 
     throws IOException { 
    super(request); 
    body = StreamUtil.readBytes(request.getReader(), "UTF-8"); 
} 

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

@Override 
public ServletInputStream getInputStream() throws IOException { 
    final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body); 
    return new ServletInputStream() { 

     @Override 
     public int read() throws IOException { 
      return byteArrayInputStream.read(); 
     } 

     @Override 
     public boolean isFinished() { 
      return false; 
     } 

     @Override 
     public boolean isReady() { 
      return false; 
     } 

     @Override 
     public void setReadListener(ReadListener arg0) { 
     } 
    }; 
} 

}

फिल्टर में:

ServletRequest requestWrapper = new HttpServletRequestWrapper(request); 
2

यह मेरे लिए काम किया। यह getInputStream लागू करता है।

private class MyHttpServletRequestWrapper extends HttpServletRequestWrapper { 

    private byte[] body; 

    public MyHttpServletRequestWrapper(HttpServletRequest request) { 
     super(request); 
     try { 
      body = IOUtils.toByteArray(request.getInputStream()); 
     } catch (IOException ex) { 
      body = new byte[0]; 
     } 
    } 

    @Override 
    public ServletInputStream getInputStream() throws IOException { 
     return new ServletInputStream() { 
      ByteArrayInputStream bais = new ByteArrayInputStream(body); 

      @Override 
      public int read() throws IOException { 
       return bais.read(); 
      } 
     }; 
    } 

} 

तो फिर आप अपने विधि में उपयोग करें:

//copy body 
servletRequest = new MyHttpServletRequestWrapper(servletRequest); 
0

request.getInputStream() केवल एक बार पढ़ने के लिए अनुमति दी है। इस विधि का कई बार उपयोग करने के लिए, हमें HttpServletReqeustWrapper क्लास को अतिरिक्त कार्य करने की आवश्यकता है। नीचे मेरा नमूना रैपर वर्ग देखें।

public class MultiReadHttpServletRequest extends HttpServletRequestWrapper { 
    private ByteArrayOutputStream cachedBytes; 

    public MultiReadHttpServletRequest(HttpServletRequest request) { 
     super(request); 
    } 

    @Override 
    public ServletInputStream getInputStream() throws IOException { 
     if (cachedBytes == null) 
      cacheInputStream(); 

     return new CachedServletInputStream(); 
    } 

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

    private void cacheInputStream() throws IOException { 
     /* 
     * Cache the inputstream in order to read it multiple times. For convenience, I use apache.commons IOUtils 
     */ 
     cachedBytes = new ByteArrayOutputStream(); 
     IOUtils.copy(super.getInputStream(), cachedBytes); 
    } 

    /* An inputstream which reads the cached request body */ 
    public class CachedServletInputStream extends ServletInputStream { 
     private ByteArrayInputStream input; 

     public CachedServletInputStream() { 
      /* create a new input stream from the cached request body */ 
      input = new ByteArrayInputStream(cachedBytes.toByteArray()); 
     } 

     @Override 
     public int read() throws IOException { 
      return input.read(); 
     } 
    } 
} 

मेरे मामले में, मैं लॉग इन सभी आने वाले अनुरोधों का पता लगाता हूं। मैं एक फ़िल्टर बनाया गया

सार्वजनिक वर्ग TracerRequestFilter लागू करता है फ़िल्टर { निजी स्थिर अंतिम लॉगर लॉग = LoggerFactory.getLogger (TracerRequestFilter.class);

@Override 
public void destroy() { 

} 

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

    try { 
     if (LOG.isDebugEnabled()) { 
      final MultiReadHttpServletRequest wrappedRequest = new MultiReadHttpServletRequest(req); 
      // debug payload info 
      logPayLoad(wrappedRequest); 
      chain.doFilter(wrappedRequest, response); 
     } else { 
      chain.doFilter(request, response); 
     } 
    } finally { 
     LOG.info("end-of-process"); 
    } 
} 

private String getRemoteAddress(HttpServletRequest req) { 
    String ipAddress = req.getHeader("X-FORWARDED-FOR"); 
    if (ipAddress == null) { 
     ipAddress = req.getRemoteAddr(); 
    } 
    return ipAddress; 
} 

private void logPayLoad(HttpServletRequest request) { 
    final StringBuilder params = new StringBuilder(); 
    final String method = request.getMethod().toUpperCase(); 
    final String ipAddress = getRemoteAddress(request); 
    final String userAgent = request.getHeader("User-Agent"); 
    LOG.debug(String.format("============debug request==========")); 
    LOG.debug(String.format("Access from ip:%s;ua:%s", ipAddress, userAgent)); 
    LOG.debug(String.format("Method : %s requestUri %s", method, request.getRequestURI())); 
    params.append("Query Params:").append(System.lineSeparator()); 
    Enumeration<String> parameterNames = request.getParameterNames(); 

    for (; parameterNames.hasMoreElements();) { 
     String paramName = parameterNames.nextElement(); 
     String paramValue = request.getParameter(paramName); 
     if ("password".equalsIgnoreCase(paramName) || "pwd".equalsIgnoreCase(paramName)) { 
      paramValue = "*****"; 
     } 
     params.append("---->").append(paramName).append(": ").append(paramValue).append(System.lineSeparator()); 
    } 
    LOG.debug(params.toString()); 
    /** request body */ 

    if ("POST".equals(method) || "PUT".equals(method)) { 
     try { 
      LOG.debug(IOUtils.toString(request.getInputStream())); 
     } catch (IOException e) { 
      LOG.error(e.getMessage(), e); 
     } 
    } 
    LOG.debug(String.format("============End-debug-request==========")); 
} 

@Override 
public void init(FilterConfig arg0) throws ServletException { 

} 

}

यह मेरे दोनों सर्वलेट 2.5 और 3.0 के लिए काम करता है। मैं सभी अनुरोध पैराम दोनों फॉर्म-एन्कोडेड और जेसन बॉडी का अनुरोध करता हूं।

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