Open Liberty 中的 Servlet 编码问题

Servlet encoding woes in Open Liberty

我有一个简单的测试 servlet,它应该输出一个非 ASCII 字符(右单引号 - ’)。在 Tomcat 中,它有效,但在 Liberty 中,我得到了垃圾。这是 Liberty 中的错误,我做错了吗,还是配置问题?

package test;

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


public class TestServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        response.setCharacterEncoding("UTF-8");
        try (PrintWriter out = response.getWriter()) {
            out.print("’");
            out.close();
        }
    }
}

和web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
    <servlet>
        <servlet-name>TestServlet</servlet-name>
        <servlet-class>test.TestServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>TestServlet</servlet-name>
        <url-pattern>/TestServlet</url-pattern>
    </servlet-mapping>
</web-app>

来自 Tomcat 的响应是(由 Fiddler 提供):

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=UTF-8
Content-Length: 3
Date: Wed, 23 Jun 2021 23:40:07 GMT

’

body 十六进制为:E2, 80, 99(这是正确的 UTF-8 for ’)

来自Liberty它是

HTTP/1.1 200 OK
X-Powered-By: Servlet/3.1
Content-Type: text/html;charset=UTF-8
Content-Length: 3
Content-Language: en-CA
Date: Wed, 23 Jun 2021 23:52:49 GMT

’

该内容的十六进制为:C3、A2、E2、82、AC、E2、84、A2

开发工具 (F12) 匹配 Fiddler。

我试过移动代码

        response.setContentType("text/html;charset=UTF-8");
        response.setCharacterEncoding("UTF-8");

在 getWriter 之前和之后(文档说它应该在 getWriter 之前)。有无 setCharacterEncoding 以及各种事物、内容类型等

.java 文件本身以 UTF-8 编码保存。

令人好奇的是内容长度 header 在任一服务器上都表示 3 个字节,但在 Liberty 中实际内容长度为 8 个字节。好像字节已经 re-encoded?

那么,这是怎么回事?

更新: 根据@pmdinh 的回答删除 out.close() 有效果,但没有修复。这是我最接近正确行为的方法

    response.setCharacterEncoding("UTF-8");    
            
    try (PrintWriter out = response.getWriter()) {
        response.setContentType("text/html;charset=UTF-8");    
        
        out.print("’1234");

    }

这正确编码它,但现在内容长度错了 2 个字节。所以响应是

HTTP/1.1 200 OK
X-Powered-By: Servlet/3.1
Content-Type: text/html;charset=UTF-8
Content-Length: 5
Content-Language: en-CA
Date: Thu, 24 Jun 2021 17:50:55 GMT

’1234

但是由于 content-length 是 2 short 浏览器显示 ’12

另请注意,setCharacterEncoding 和 setContentType 的放置很重要,其他组合会使输出更糟(编码不正确)。

删除

out.close();

应该可以解决问题。

参考:https://www.ibm.com/support/pages/apar/PM71666