我们可以设置默认字符编码以用于读取请求正文ServletContext#setRequestCharacterEncoding
(从 Servlet 4.0 开始)。
我认为HttpServletRequest#getReader
可以使用ServletContext#setRequestCharacterEncoding(*)
.
但是HttpServletRequest#getReader
返回的阅读器似乎解码的字符不使用设置的编码ServletContext#setRequestCharacterEncoding
。
我的问题是:
- 为什么
ServletContext#setRequestCharacterEncoding
对 没有影响HttpServletRequest#getReader
(但对 有影响HttpServletRequest#getParameter
)? - 有没有描述这种
ServletContext#setRequestCharacterEncoding
行为的规范HttpServletRequest#getReader
?
(我阅读了 Servlet 规范版本 4.0,但我找不到任何关于此类行为的规范。)
我创建了一个简单的战争应用程序并进行了测试ServletContext#setRequestCharacterEncoding
。
[环境]
- Tomcat9.0.19(我没有更改任何默认配置)
- JDK11
- 视窗8.1
[索引.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());
}
}
}
我没有任何 servlet 过滤器。以上三个都是这个war应用的组件。( GitHub )
案例1:当我提交带有参数'hello'的表单时,'hello'的值被成功解码如下。
requestCharacterEncoding : UTF-8
req.getCharacterEncoding() : UTF-8
hello : あ
案例2:当我点击'post'发送文本内容时,请求体无法成功解码如下。(尽管我确认请求正文是这样由 UTF-8 编码的E3 81 82
:)
requestCharacterEncoding : UTF-8
req.getCharacterEncoding() : UTF-8
body : ???
案例 3:当我也使用HttpServletRequest#setCharacterEncoding
servlet 的“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
at 时InitServletContextListener.java
,没有设置字符编码。
requestCharacterEncoding : null
req.getCharacterEncoding() : null
body : ???
[笔记]
(*)我认为是因为:
HttpServletRequest#getReader
(1)说 的 java doc“阅读器根据正文使用的字符编码翻译字符数据”。
HttpServletRequest#getCharacterEncoding
(2)说 的 java doc“返回此请求正文中使用的字符编码的名称”。
- (3) 的 java doc
HttpServletRequest#getCharacterEncoding
也说“以下用于指定请求字符编码的方法按优先级降序排列:每个请求,每个 Web 应用程序(使用 ServletContext.setRequestCharacterEncoding,部署描述符)”。
ServletContext#setResponseCharacterEncoding
工作正常。当我使用ServletContext#setResponseCharacterEncoding
时,HttpServletResponse#getWriter
返回的编写器通过它设置的字符编码对响应正文进行编码。