Фильтр Tomcat отрицательно влияет на поток ввода запросов (поток ввода пуст) - PullRequest
7 голосов
/ 21 июля 2011

Я добавил в свое приложение фильтр, который просто регистрирует определенные вещи о запросе.Некоторые из моих сервлетов читают из ServletRequest#getInputStream.После добавления этого фильтра те сервлеты, которые читают из ServletRequest#getInputStream, больше не работают, поскольку входной поток пуст.Отключение фильтра, просто закомментировав его из моего web.xml, решает проблему.

Почему это происходит, и есть ли способ использовать фильтр, чтобы он не испортил ServletRequest#getInputStream?

Фильтр на самом деле RequestDumperFilter Tomcat, включенный в одно из примеров веб-приложений.Я включу только метод doFilter, так как это важная часть.Если вы хотите увидеть все это, я поставлю его на PasteBin .

/**
 * Time the processing that is performed by all subsequent filters in the
 * current filter stack, including the ultimately invoked servlet.
 *
 * @param request The servlet request we are processing
 * @param result The servlet response we are creating
 * @param chain The filter chain we are processing
 *
 * @exception IOException if an input/output error occurs
 * @exception ServletException if a servlet error occurs
 */
public void doFilter(ServletRequest request, ServletResponse response,
                     FilterChain chain)
throws IOException, ServletException {

    if (filterConfig == null)
    return;

// Render the generic servlet request properties
StringWriter sw = new StringWriter();
PrintWriter writer = new PrintWriter(sw);
writer.println("Request Received at " +
           (new Timestamp(System.currentTimeMillis())));
writer.println(" characterEncoding=" + request.getCharacterEncoding());
writer.println("     contentLength=" + request.getContentLength());
writer.println("       contentType=" + request.getContentType());
writer.println("            locale=" + request.getLocale());
writer.print("           locales=");
Enumeration locales = request.getLocales();
boolean first = true;
while (locales.hasMoreElements()) {
    Locale locale = (Locale) locales.nextElement();
    if (first)
        first = false;
    else
        writer.print(", ");
    writer.print(locale.toString());
}
writer.println();
Enumeration names = request.getParameterNames();
while (names.hasMoreElements()) {
    String name = (String) names.nextElement();
    writer.print("         parameter=" + name + "=");
    String values[] = request.getParameterValues(name);
    for (int i = 0; i < values.length; i++) {
        if (i > 0)
        writer.print(", ");
    writer.print(values[i]);
    }
    writer.println();
}
writer.println("          protocol=" + request.getProtocol());
writer.println("        remoteAddr=" + request.getRemoteAddr());
writer.println("        remoteHost=" + request.getRemoteHost());
writer.println("            scheme=" + request.getScheme());
writer.println("        serverName=" + request.getServerName());
writer.println("        serverPort=" + request.getServerPort());
writer.println("          isSecure=" + request.isSecure());

// Render the HTTP servlet request properties
if (request instanceof HttpServletRequest) {
    writer.println("---------------------------------------------");
    HttpServletRequest hrequest = (HttpServletRequest) request;
    writer.println("       contextPath=" + hrequest.getContextPath());
    Cookie cookies[] = hrequest.getCookies();
        if (cookies == null)
            cookies = new Cookie[0];
    for (int i = 0; i < cookies.length; i++) {
        writer.println("            cookie=" + cookies[i].getName() +
               "=" + cookies[i].getValue());
    }
    names = hrequest.getHeaderNames();
    while (names.hasMoreElements()) {
        String name = (String) names.nextElement();
    String value = hrequest.getHeader(name);
        writer.println("            header=" + name + "=" + value);
    }
    writer.println("            method=" + hrequest.getMethod());
    writer.println("          pathInfo=" + hrequest.getPathInfo());
    writer.println("       queryString=" + hrequest.getQueryString());
    writer.println("        remoteUser=" + hrequest.getRemoteUser());
    writer.println("requestedSessionId=" +
           hrequest.getRequestedSessionId());
    writer.println("        requestURI=" + hrequest.getRequestURI());
    writer.println("       servletPath=" + hrequest.getServletPath());
}
writer.println("=============================================");

// Log the resulting string
writer.flush();
filterConfig.getServletContext().log(sw.getBuffer().toString());

// Pass control on to the next filter
    chain.doFilter(request, response);

}

Заключение

Из того, что я прочитал Погуглив , любой из следующих методов при первом вызове сделает getInputStream пустым:

  • getParameter
  • getParameterNames
  • getParameterValues
  • getParameterMap

Спасибо SimoneGianni за указание мне в правильном направлении:

Вот несколько источников

У этого человека действительно была похожая проблема, и он создал собственный класс-обертку в качестве обходного пути.

Ответы [ 2 ]

3 голосов
/ 21 июля 2011

Если вы вызываете getParameters, getParameterNames и подобные методы, вы МОЖЕТЕ вмешаться в getInputStream или getReader. Это недостаточно четко указано в документации сервлета, но есть некоторые предупреждения об обратном (getInputStream, мешающий getParameter) в официальных javadocs сервлета (начиная с версии 1.3, см. http://download.oracle.com/javaee/1.3/api/javax/servlet/ServletRequest.html#getParameter(java.lang.String))

Вы видите эту проблему на постах? Так как POST-запросы кодируют параметры как тело запроса, для чтения параметров, которые вы фактически должны использовать (контейнер делает это за вас) входной поток.

0 голосов
/ 21 июля 2011

Ничего себе. Этот подходит. Держу пари, что RequestDumper должен проанализировать весь InputStream, чтобы, ну, в общем, вывести запрос, и поэтому InputStream пуст. Я думаю, что вы не можете RequestDumper перед любым сервлетом, который планирует делать getInputStream. Я в недоумении, что ваши варианты с этой точки зрения, хотя. Возможно выгрузите интересующие вас параметры непосредственно из HttpRequest ПОСЛЕ chain.doFilter (запрос, ответ); позвоните.

...