HTML:表单不发送 UTF-8 格式输入热核心理念

2022-09-03 08:54:44

我已经访问了有关HTML中UTF-8编码的每个问题,似乎没有什么可以使它像预期的那样工作。

我添加了标签:没有任何变化。
我在中添加了属性:没有任何变化。metaaccept-charsetform


JSP 文件

<%@ page pageEncoding="UTF-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>Editer les sous-titres</title>
</head>
<body>
    <form method="post" action="/Subtitlor/edit" accept-charset="UTF-8"> 
        <h3 name="nameOfFile"><c:out value="${ nameOfFile }"/></h3> 
        <input type="hidden" name="nameOfFile" id="nameOfFile" value="${ nameOfFile }"/>
        <c:if test="${ !saved }">
            <input value ="Enregistrer le travail" type="submit" style="position:fixed; top: 10px; right: 10px;" />
        </c:if>
        <a href="/Subtitlor/" style="position:fixed; top: 50px; right: 10px;">Retour à la page d'accueil</a>
        <c:if test="${ saved }">
            <div style="position:fixed; top: 90px; right: 10px;">
                <c:out value="Travail enregistré dans la base de donnée"/>
            </div>
        </c:if>
        <table border="1">
            <c:if test="${ !saved }">
                <thead>
                    <th style="weight:bold">Original Line</th>
                    <th style="weight:bold">Translation</th>
                    <th style="weight:bold">Already translated</th>
                </thead>
            </c:if>
            <c:forEach items="${ subtitles }" var="line" varStatus="status">
                <tr>
                    <td style="text-align:right;"><c:out value="${ line }" /></td>
                    <td><input type="text" name="line${ status.index }" id="line${ status.index }" size="35" /></td>
                    <td style="text-align:right"><c:out value="${ lines[status.index].content }"/></td>
                </tr>
            </c:forEach>
        </table>
    </form>
</body>
</html>

Servlet

for (int i = 0 ; i < 2; i++){
    System.out.println(request.getParameter("line"+i));
}

输出

Et ton père et sa soeur
Il ne sera jamais parti.

答案 1

我添加了标记:没有任何变化。

当页面通过HTTP而不是从本地磁盘文件系统(即页面的URL而不是例如)提供时,它确实没有任何影响。在 HTTP 中,将使用 HTTP 响应标头中的字符集。您已经将其设置为如下所示:http://...file://...

<%@page pageEncoding="UTF-8"%>

这不仅会使用 UTF-8 写出 HTTP 响应,还会在响应标头中设置属性。charsetContent-Type

Web浏览器将使用这个来解释响应并编码任何HTML表单参数。


我以形式添加了 accept-charset 属性:没有任何变化。

它仅在Microsoft Internet Explorer浏览器中有效。即便如此,它也做错了。永远不要使用它。所有真正的 Web 浏览器都将改为使用响应标头中指定的属性。即使您指定属性,即使MSIE也会以正确的方式执行此操作。如前所述,您已经通过 正确设置了它。charsetContent-Typeaccept-charsetpageEncoding


删除标记和属性。它们没有任何有用的效果,从长远来看,它们只会让自己感到困惑,甚至在最终用户使用MSIE时使事情变得更糟。只需坚持.除了在所有 JSP 页面上重复这些,不如按如下方式全局设置它:metaaccept-charsetpageEncodingpageEncodingweb.xml

<jsp-config>
    <jsp-property-group>
        <url-pattern>*.jsp</url-pattern>
        <page-encoding>UTF-8</page-encoding>
    </jsp-property-group>
</jsp-config>

如前所述,这将告诉 JSP 引擎使用 UTF-8 编写 HTTP 响应输出,并将其设置在 HTTP 响应标头中。Web浏览器将使用相同的字符集对HTTP请求参数进行编码,然后再发送回服务器。

您唯一缺少的步骤是告诉服务器,在返回调用之前,它必须使用 UTF-8 对 HTTP 请求参数进行解码。如何全局执行此操作取决于 HTTP 请求方法。鉴于您使用的是 POST 方法,使用下面的 servlet 过滤器类可以相对容易地实现这一点,该类会自动挂接所有请求:getParameterXxx()

@WebFilter("/*")
public class CharacterEncodingFilter implements Filter {

    @Override
    public void init(FilterConfig config) throws ServletException {
        // NOOP.
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        request.setCharacterEncoding("UTF-8");
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
        // NOOP.
    }
}

就这样。在 Servlet 3.0+ (Tomcat 7 及更高版本) 中,您不需要额外的配置。web.xml

您只需要记住,在首次使用任何方法获取POST请求参数之前调用方法非常重要。这是因为它们仅在首次访问时解析一次,然后缓存在服务器内存中。setCharacterEncoding()getParameterXxx()

例如,下面的顺序是错误的

String foo = request.getParameter("foo"); // Wrong encoding.
// ...
request.setCharacterEncoding("UTF-8"); // Attempt to set it.
String bar = request.getParameter("bar"); // STILL wrong encoding!

在 servlet 过滤器中执行该工作将保证它及时运行(至少在任何 servlet 之前)。setCharacterEncoding()


如果你想指示服务器使用UTF-8解码GET(不是POST)请求参数(你知道的那些在URL中的字符后面看到的参数),那么你基本上需要在服务器端配置它。无法通过 servlet API 对其进行配置。如果您使用例如Tomcat作为服务器,那么只需在Tomcat自己的元素中添加属性即可。?URIEncoding="UTF-8"<Connector>/conf/server.xml

如果您仍然在调用的控制台输出中看到Mojibake,那么标准输出本身未配置为使用UTF-8的可能性很大。如何做到这一点取决于谁负责解释和呈现标准输出。例如,如果您使用Eclipse作为IDE,那么只需将“窗口>首选项”>“常规>工作区>文本文件编码”设置为UTF-8。System.out.println()

另请参阅:


答案 2

让我首先说一个普遍的事实,我们都知道计算机除了比特(0和1)之外什么都不懂。

现在,当您通过HTTP提交HTML表单并且值通过网络传输到目标服务器时,基本上会传递大量位 - 0和1。

  • 在将数据发送到服务器之前,HTTP客户端(浏览器或curl等)将使用某种编码方案对其进行编码,并期望服务器使用相同的方案对其进行解码,以便服务器确切地知道客户端发送了什么。
  • 在将响应发送回客户端之前,服务器将使用某种编码方案对其进行编码,并期望客户端使用相同的方案对其进行解码,以便客户端确切地知道服务器发送了什么。

可以打个比方 - 我给你发一封信,告诉你它是用英语,法语还是荷兰语写的,这样你就会得到我打算给你的确切信息。在回复我的同时,你还会提到我应该用哪种语言阅读。

重要的一点是,当数据离开客户端时,它将被编码,并且将在服务器端解码,反之亦然。如果您不指定任何内容,则在从客户端离开服务器端之前,内容将按照 application/x-www-form-urlencoded 进行编码

核心理念

阅读热身很重要。您需要做一些事情来确保获得预期的结果。

  • 在将数据从客户端发送到服务器之前设置正确的编码。
  • 在服务器端设置正确的解码和编码,以读取请求并将响应写回客户端(这就是您未获得预期结果的原因)
  • 确保在任何地方使用相同的编码方案,在客户端使用ISO-8859-1进行编码,而在服务器上使用UTF-8进行解码,否则会出现愚蠢(从我的类比中,我用英语写你,你正在用法语阅读))
  • 如果尝试使用Windows命令行或Eclipse日志查看器等使用日志进行验证,请为日志查看器设置正确的编码(这是导致您问题的原因,但这不是主要原因,因为首先从请求对象读取的数据未正确解码。 在这里阅读 )

在将数据从客户端发送到服务器之前设置正确的编码

为了确保这一点,有几种方法讨论,但我会说使用HTTP Accept-Charset request-header字段。根据您提供的代码片段,您已经在使用并正确使用它,因此您在这方面做得很好。

有些人会说不要使用这个,或者它没有实现,但我会非常谦卑地不同意他们。 是HTTP 1.1规范的一部分(我已经提供了链接),实现HTTP 1.1的浏览器将实现相同的功能。他们也可能争辩说,使用接受请求标头字段的“字符集”属性,但Accept-Charset

  • 它确实不存在,请检查我提供的“接受请求标头字段”链接。
  • 检查

我为您提供所有数据和事实,而不仅仅是文字,但是如果您不满意,请使用不同的浏览器进行以下测试。

  • 在 HTML 表单和 POST/GET 表单中设置具有中文或高级法语字符的服务器。accept-charset="ISO-8859-1"
  • 在服务器上使用 UTF-8 方案对数据进行解码。
  • 现在,通过交换客户端和服务器编码来重复相同的测试。

您将看到,在服务器上,您都无法看到预期的字符。但是,如果您将使用相同的编码方案,那么您将看到预期的字符。因此,浏览器会执行实现,其效果会生效。accept-charset

在服务器端设置正确的解码和编码,以读取请求并将响应写回客户端

有很多方法可以做到这一点(有时可能需要根据特定场景进行一些配置,但下面解决了95%的情况,并且也适用于您的情况)。例如:

  1. 使用字符编码筛选器根据请求和响应设置编码。
  2. 根据请求和响应使用setCharacterEncoding
  3. 配置 Web 或应用程序服务器以使用等进行正确的字符编码。在此处阅读更多内容-Dfile.encoding=utf8
  4. 等。

我最喜欢的是第一个,也会解决你的问题 - “字符编码过滤器”,原因如下:

  • 所有编码处理逻辑都在一个地方。
  • 你通过配置拥有所有权力,在一个地方改变,每个人都很高兴。
  • 在我设置字符编码之前,您不必担心其他一些代码可能会读取我的请求流或清除响应流。

1. 字符编码过滤器

您可以执行以下操作来实现自己的字符编码筛选器。如果你正在使用一些框架,如Springs等,那么你不需要编写自己的类,而只需在Web中进行配置.xml

下面的核心逻辑与Spring所做的非常相似,除了很多依赖性之外,豆类意识到他们所做的事情。

网页.xml(配置)

<filter>
    <filter-name>EncodingFilter</filter-name>
    <filter-class>
        com.sks.hagrawal.EncodingFilter
    </filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
        <param-name>forceEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>EncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

编码筛选器(字符编码实现类)

public class EncodingFilter implements Filter {
    private String encoding = "UTF-8";
    private boolean forceEncoding = false;

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
        request.setCharacterEncoding(encoding);
        if(forceEncoding){ //If force encoding is set then it means that set response stream encoding as well ...
            response.setCharacterEncoding(encoding);
        }
        filterChain.doFilter(request, response);
    }

    public void init(FilterConfig filterConfig) throws ServletException {
        String encodingParam = filterConfig.getInitParameter("encoding");
        String forceEncoding = filterConfig.getInitParameter("forceEncoding");
        if (encodingParam != null) {
            encoding = encodingParam;
        }
        if (forceEncoding != null) {
            this.forceEncoding = Boolean.valueOf(forceEncoding);
        }
    }

    @Override
    public void destroy() {
        // TODO Auto-generated method stub

    }
}

2. ServletRequest.setCharacterEncoding()

这本质上是在字符编码过滤器中完成的相同代码,但不是在过滤器中执行,而是在servlet或控制器类中执行。

想法是再次用于在开始读取http请求流之前设置http请求流的编码。request.setCharacterEncoding("UTF-8");

尝试下面的代码,您将看到,如果您不使用某种过滤器来设置对请求对象的编码,则第一个日志将为NULL,而第二个日志将为“UTF-8”。

System.out.println("CharacterEncoding = " + request.getCharacterEncoding());
request.setCharacterEncoding("UTF-8");
System.out.println("CharacterEncoding = " + request.getCharacterEncoding());

以下是 setCharacterEncoding Java 文档的重要摘录。另一件需要注意的事情是,您应该提供有效的编码方案,否则您将获得UnsupportedEncodingException

覆盖此请求正文中使用的字符编码的名称。在使用 getReader() 读取请求参数或读取输入之前,必须调用此方法。否则,它没有任何效果。

无论哪里需要,我都尽力为您提供官方链接或StackOverflow接受的赏金答案,以便您可以建立信任。