Почему "ServletContext#setRequestCharacterEncoding" не влияет на "HttpServletRequest#getReader"?
Мы можем установить кодировку символов по умолчанию, используемую для чтения тел запросов: 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
,
[Ко]
- 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)
Случай 1: Когда я отправляю форму с параметром 'hello', значение 'hello' успешно декодируется следующим образом.
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
говоритMsgstr "Возвращает имя кодировки символов, используемой в теле этого запроса".
- (3) Java документ
HttpServletRequest#getCharacterEncoding
также говорит"Следующие методы для указания кодировки символов запроса используются в порядке убывания приоритета: для каждого запроса, для каждого веб-приложения (с использованием ServletContext.setRequestCharacterEncoding, дескриптор развертывания)".
- (1) Java документ
ServletContext#setResponseCharacterEncoding
работает отлично. Когда я используюServletContext#setResponseCharacterEncoding
Автор, которыйHttpServletResponse#getWriter
Return кодирует тело ответа с помощью установленной им кодировки символов.
1 ответ
Это ошибка Apache Tomcat (относится к getReader()
) это будет исправлено в 9.0.21 и далее благодаря вашему отчету в списке рассылки пользователей Tomcat.
Для любопытных вот исправление.