Проблема с чтением тела запроса в сервлете - PullRequest
2 голосов
/ 06 августа 2010

Я пишу HTTP-прокси, который является частью системы тестирования / проверки.Прокси-сервер фильтрует все запросы, поступающие от клиентского устройства, и направляет их к различным тестируемым системам.

Прокси-сервер реализован в виде сервлета, где каждый запрос перенаправляется в целевую систему, он обрабатывает как GET, так и POST.Иногда ответ от целевой системы изменяется, чтобы соответствовать различным условиям теста, но это не является частью проблемы.

При пересылке запроса копируются все заголовки, кроме тех, которые являются частью фактического HTTPпередача, такая как заголовки Content-Length и Connection.

Если запрос представляет собой HTTP-запрос POST, то тело объекта запроса также пересылается, и здесь иногда он не работает.

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

URL url = new URL(targetURL);
HttpURLConnection conn  = (HttpURLConnection)url.openConnection();
String method = request.getMethod();

java.util.Enumeration headers = request.getHeaderNames();
while(headers.hasMoreElements()) {

    String headerName = (String)headers.nextElement();
    String headerValue = request.getHeader(headerName);

    if (...) { // do various adaptive stuff based on header 

    }

    conn.setRequestProperty(headerName, headerValue);
}

// здесь часть, которая выходит из строя

char postBody[] = new char[1024];
int len;

if(method.equals("POST")) {
    logger.debug("guiProxy, handle post, read request body");
    conn.setDoOutput(true);

    BufferedReader br = request.getReader();
    BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(conn.getOutputStream()));

    do {
        logger.debug("Read request into buffer of size: " + postBody.length);

        len = br.read(postBody, 0, postBody.length);
        logger.debug("guiProxy, send request body, got " + len + " bytes from request");

        if(len != -1) {
            bw.write(postBody, 0, len);
        }
    } while(len != -1);
    bw.close();
}

Итак, что происходит в первый раз, когда POSTпринимается, -1 символ читается из считывателя запроса, трассировка проволочной сетки показывает, что тело сущности, содержащее параметры записи, закодированные в URL, существует и находится в одном сегменте TCP, поэтому никаких различий, связанных с сетью, нет.во второй раз br.read успешно возвращает 232 байта в теле объекта запроса POST и каждый последующий запросквест также работает.

Единственное различие между первым и предстоящим запросами POST заключается в том, что в первом случае нет файлов cookie, а во втором - файл cookie, который сопоставляется с JSESSION.

Может ли быть побочным эффектом недоступность тела сущности, поскольку при обработке запроса в контейнере сервлета уже прочитаны параметры POST, но почему он работает с предстоящими запросами.

Я считаю, чтоКонечно, решение состоит в том, чтобы игнорировать тело объекта в запросах POST, содержащих данные, закодированные в URL, и вместо этого извлекать все параметры из запроса сервлета, используя getParameter, и заново вставлять их в исходящий запрос.может содержать параметры GET, не в нашем приложении прямо сейчас, но его правильная реализация - это некоторая работа.

Итак, мой вопрос в основном: почему читатель из request.getReader () возвращает -1 при чтении и сущноститело присутствует в запросе, еслитело объекта недоступно для чтения, тогда getReader должен выдать исключение недопустимого состояния.Я также пытался с InputStream с использованием getInputStream () с теми же результатами.

Все это проверено на apache-tomcat-6.0.18.

Ответы [ 2 ]

5 голосов
/ 06 августа 2010

Итак, мой вопрос в основном: почему читатель из request.getReader () возвращает -1 при чтении.

Возвращает -1, когда тела нет или когда уже прочитано . Вы не можете прочитать это дважды. Убедитесь, что ничего в цепочке запросов / ответов не прочитало его.

и тело запроса присутствует в запросе, если тело объекта недоступно для чтения, тогда getReader должен выдать исключение недопустимого состояния.

Он выдаст это только тогда, когда вы уже вызывали getInputStream() по запросу, а не когда он недоступен.

Я также пытался использовать InputStream с использованием getInputStream () с теми же результатами.

В конце концов, я бы предпочел потоковые байты, а не символы, потому что тогда вам не нужно принимать во внимание кодировку символов (что вы не делаете до сих пор, это может привести к будущим проблемам, когда вы получите все это на работу).

1 голос
/ 28 апреля 2012

Кажется, что движется

BufferedReader br = request.getReader()

перед всеми операциями этот запрос на чтение (например, request.getHeader ()) работает для меня хорошо.

...