java - 为什么 'ServletContext#setRequestCharacterEncoding' 对 'HttpServletRequest#getReader' 没有影响?

标签 java servlet-4

我们可以通过 ServletContext#setRequestCharacterEncoding 设置用于读取请求正文的默认字符编码(从 Servlet 4.0 开始)。

我认为HttpServletRequest#getReader的字符编码可以使用 ServletContext#setRequestCharacterEncoding(*) 设置.

但是读者认为HttpServletRequest#getReader返回似乎不使用 ServletContext#setRequestCharacterEncoding 设置的编码来解码字符.

我的问题是:

  • 为什么 ServletContext#setRequestCharacterEncodingHttpServletRequest#getReader 没有影响(但它对 HttpServletRequest#getParameter 有影响)?
  • 是否有任何规范描述此类 ServletContext#setRequestCharacterEncodingHttpServletRequest#getReader行为?

(我阅读了 Servlet 规范版本 4.0,但找不到任何有关此类行为的规范。)

我创建了一个简单的 war 应用程序并进行了测试 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());
        }
    }
}

我没有任何 servlet 过滤器。 以上三个就是这个war应用的全部组件。 (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 设置编码时相反,在 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#setRequestCharacterEncodingInitServletContextListener.java ,未设置字符编码。

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

[注意]

  • (*)我这么认为是因为:

    • (1)HttpServletRequest#getReader的java文档说

      "The reader translates the character data according to the character encoding used on the body".

    • (2)HttpServletRequest#getCharacterEncoding的java文档说

      "Returns the name of the character encoding used in the body of this request".

    • (3)HttpServletRequest#getCharacterEncoding的java文档还说

      "The following methods for specifying the request character encoding are consulted, in decreasing order of priority: per request, per web app (using ServletContext.setRequestCharacterEncoding, deployment descriptor)".

  • ServletContext#setResponseCharacterEncoding工作正常。当我使用ServletContext#setResponseCharacterEncoding时,笔者认为HttpServletResponse#getWriter returns 按其设置的字符编码对响应正文进行编码。

最佳答案

这是一个 Apache Tomcat 错误(特定于 getReader()),由于您在 Tomcat 用户邮件列表上的报告,该错误将在 9.0.21 以后得到修复。

对于好奇的人,这里是 fix .

关于java - 为什么 'ServletContext#setRequestCharacterEncoding' 对 'HttpServletRequest#getReader' 没有影响?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56087155/

相关文章:

java - 该项目不适用于 servlet 4.0 和 jsf 2.3

java - 无法将项目方面动态 Web 模块的版本更改为 3.1

servlets - 必须声明元素 web-app(Servlet 4.0)

java - 为什么我将运行标志设置为 false 后线程仍继续运行?

java - Runtime.exec() 无法运行 "su - postgres -c ' pg_dump .. .'"

java - Spring Boot REST 服务器在带有 @Validated 的意外请求正文的 POST 上抛出 HttpRequestMethodNotSupportedException

java - 计算Java中矩阵中未访问的单元格

java - Java与C#到DateTime的长转换