Почему «ServletContext # setRequestCharacterEncoding» не влияет на «HttpServletRequest # getReader»? - PullRequest
1 голос
/ 11 мая 2019

Мы можем установить кодировку символов по умолчанию, используемую для чтения тел запросов, с помощью ServletContext#setRequestCharacterEncoding (начиная с Servlet 4.0).

Я думаю, что кодировка символов для HttpServletRequest#getReader может быть установлена ​​с помощью ServletContext#setRequestCharacterEncoding(*).

Но читатель, который возвращает HttpServletRequest#getReader, похоже, декодирует символы, не используя кодировку, установленную ServletContext#setRequestCharacterEncoding.

Мои вопросы:

  • Почему ServletContext#setRequestCharacterEncoding не влияет на HttpServletRequest#getReader (но влияет на HttpServletRequest#getParameter)?
  • Существует ли какая-либо спецификация, описывающая такое поведение ServletContext#setRequestCharacterEncoding и HttpServletRequest#getReader?

(Я читал спецификацию сервлетов версии 4.0, но не могу найти никакой спецификации о таком поведении.)

Я создал простое военное приложение и протестировал ServletContext#setRequestCharacterEncoding.

[Env]

  • Tomcat9.0.19 (я не изменяю конфигурацию по умолчанию)
  • JDK11
  • Windows8.1

[index.html]

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
</head>
<body>
    <form action="/SimpleWarApp/app/simple" method="post">
        <!-- The value is Japanese character '\u3042' -->
        <input type="text" name="hello" value="あ"/>
        <input type="submit" value="submit!"/>
    </form>
    <button type="button" id="the_button">post</button>
    <script>
        document.getElementById('the_button').addEventListener('click', function() {
            var xhttp = new XMLHttpRequest();
            xhttp.open('POST', '/SimpleWarApp/app/simple');
            xhttp.setRequestHeader('Content-Type', 'text/plain');
            <!-- The body content is Japanese character '\u3042' -->
            xhttp.send('あ');
        });
    </script>
</body>
</html>

[InitServletContextListener.java]

@WebListener
public class InitServletContextListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        sce.getServletContext().setRequestCharacterEncoding("UTF-8");
    }
}

[SimpleServlet.java]

@WebServlet("/app/simple")
@SuppressWarnings("serial")
public class SimpleServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // req.setCharacterEncoding("UTF-8");
        System.out.println("requestCharacterEncoding : " + req.getServletContext().getRequestCharacterEncoding());
        System.out.println("req.getCharacterEncoding() : " + req.getCharacterEncoding());

        String hello = req.getParameter("hello");
        if (hello != null) {
            System.out.println("hello : " + req.getParameter("hello"));
        } else {
            System.out.println("body : " + req.getReader().readLine());
        }
    }
}

У меня нет никаких фильтров сервлетов. Выше три все компоненты этого военного приложения. ( GitHub ) * +1051 *

Случай 1: Когда я отправляю форму с параметром «привет», значение «привет» успешно декодируется следующим образом.

requestCharacterEncoding : UTF-8
req.getCharacterEncoding() : UTF-8
hello : あ

Случай 2: Когда я нажимаю «отправить» и отправляю текстовое содержимое, тело запроса не может быть успешно декодировано следующим образом. (Хотя я подтверждаю, что тело запроса кодируется UTF-8 следующим образом: E3 81 82)

requestCharacterEncoding : UTF-8
req.getCharacterEncoding() : UTF-8
body : ???

Случай 3: Когда я также установил кодировку, используя HttpServletRequest#setCharacterEncoding в первой строке метода doPost сервлета, тело запроса успешно декодировалось.

requestCharacterEncoding : UTF-8
req.getCharacterEncoding() : UTF-8
body : あ

Случай 4: Когда я использую http.setRequestHeader('Content-Type', 'text/plain; charset=UTF-8'); javascript, тело запроса успешно декодируется.

requestCharacterEncoding : UTF-8
req.getCharacterEncoding() : UTF-8
body : あ

Случай 5: Когда я не вызываю req.getParameter("hello"), тело запроса не может быть успешно декодировано.

requestCharacterEncoding : UTF-8
req.getCharacterEncoding() : UTF-8
body : ???

Случай 6: Когда я не вызываю ServletContext#setRequestCharacterEncoding на InitServletContextListener.java, кодировка символов не устанавливается.

requestCharacterEncoding : null
req.getCharacterEncoding() : null
body : ???

[Примечание]

  • (*) Я так думаю, потому что:

    • (1) В Java-документе HttpServletRequest#getReader сказано

      «Считыватель переводит данные символов в соответствии с кодировкой символов, используемой в теле».

    • (2) В Java-документе HttpServletRequest#getCharacterEncoding сказано

      «Возвращает имя кодировки символов, используемой в теле этого запроса».

    • (3) Документ Java HttpServletRequest#getCharacterEncoding также говорит

      "Следующие методы для указания кодировки символов запроса используются в порядке убывания приоритета: для запроса, для веб-приложения (с использованием ServletContext.setRequestCharacterEncoding, дескриптор развертывания)".

  • ServletContext#setResponseCharacterEncoding работает нормально. Когда я использую ServletContext#setResponseCharacterEncoding, средство записи, которое возвращает HttpServletResponse#getWriter, кодирует тело ответа в соответствии с установленной им кодировкой символов.

1 Ответ

1 голос
/ 13 мая 2019

Это ошибка Apache Tomcat (относится только к getReader()), которая будет исправлена ​​в 9.0.21 и далее благодаря вашему отчету в списке рассылки пользователей Tomcat.

Для любопытных вот исправление .

...