如何强制浏览器在内容类型 http 标头中设置字符集

Posted

技术标签:

【中文标题】如何强制浏览器在内容类型 http 标头中设置字符集【英文标题】:How to force browser to set charset in content-type http header 【发布时间】:2011-01-26 00:17:02 【问题描述】:

一个简单的 html 文件:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<form method="POST" action="test.jsp" accept-charset="utf-8" method="post" enctype="application/x-www-form-urlencoded" >
    <input type="text" name="P"/>
    <input type="submit" value="subMit"/>
</form>
</body>
</html>

服务器使用标头Content-Type:text/html; charset=utf-8 提供HTML 文件。一切都说:“亲爱的浏览器,当您发布此表单时,请将其发布为 utf-8 编码”。浏览器实际上是这样做的。在输入字段中输入的每个值都将采用 UTF-8 编码。 但是浏览器不会告诉服务器! post 请求的 HTTP 标头将包含 Content-Type:application/x-www-form-urlencoded 字段,但字符集将被省略(已使用 FF3.6 和 IE8 测试)。

问题是我使用的应用程序服务器 (Tomcat6) 需要 Content-Type 标头中的字符集(如 RFC2388 中所述)。像这样:Content-Type:application/x-www-form-urlencoded;charset=utf-8。如果省略字符集,它将假定 ISO-8859-1 不是用于编码的字符集。结果是损坏的数据。

有人知道如何强制当前浏览器将字符集附加到 Content-Type 标头吗?

【问题讨论】:

我遇到了完全相同的问题,我已经在 google 群组上向 FF 询问了解决此问题的方法groups.google.com/group/mozilla.dev.platform/browse_thread/… 【参考方案1】:

有人知道如何强制当前浏览器将字符集附加到 Content-Type 标头吗?

不,没有浏览器曾经提供带有application/x-www-form-urlencoded 媒体类型的charset 参数。更重要的是,定义该类型的 HTML 规范并没有提出 charset 参数,因此服务器无法合理地期望得到一个。

(HTML4 确实期望charset 用于multipart/form-data 提交的子部分,但即使在这种情况下,实际上也没有浏览器符合要求。)

accept-charset="utf-8"

accept-charset 在 IE 中已损坏,不应使用。对于以 UTF-8 格式提供的页面中的表单,这两种方式都不会产生影响,但在其他情况下,它可能会导致结果不一致。

不,对于表单,您只需将它们所在的页面作为 UTF-8 提供,结果应该以 UTF-8 形式返回(没有识别标记可以告诉您(_charset_ hack 可能除外) ,但 Tomcat 不支持)。

因此,如果您不希望 Servlet 容器回退到其默认值(这通常是错误的),您必须告诉 Servlet 容器对参数使用什么编码。在有限的情况下,您可以调用ServletRequest.setCharacterEncoding() 来执行此操作,但这往往很脆弱,并且对于从查询字符串中获取的参数根本不起作用。遗憾的是,没有针对此问题的标准化 Servlet 级别的修复。对于 Tomcat,您通常必须 muck about with the server.xml 而无法在应用程序中修复它。

【讨论】:

好答案,期待 Tomcat 部分。 ServletRequest#setCharacterEncoding() 实际上设置了用于解析请求 body 的字符集(换句话说:POST 参数),server.xml 中的URIEncoding 实际上设置了用于解析请求的字符集URI(换句话说:GET 参数)。由于他在示例中使用 POST,因此仅使用 ServletRequest#setCharacterEncoding() 就足够了。本文更多细节:balusc.blogspot.com/2009/05/… 足够了,它可能很脆弱。如果读取任何请求参数,将导致请求正文被读取和解码,之后对setCharacterEncoding的任何调用都将无效。一些鬼鬼祟祟的中间件组件很容易通过跳入并读取参数来搞砸事情...... 您的意思是“http 规范”而不是“html 规范”,不是吗?实际上,http 规范说“必须使用适当的字符集值标记除 'ISO-8859-1' 或其子集以外的字符集中的数据。”在“3.7 媒体类型”部分:w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7 不,我的意思是 HTML 规范:HTTP 规范没有说明如何将表单数据编码到请求正文中。 RFC2616 中对 ISO-8859-1 的引用仅适用于那些定义了charset 参数的“某些媒体类型”; application/x-www-form-urlencodedmultipart/form-data 都没有定义一个,因此该规则不会影响表单提交。 form-urlencoded 甚至不包含任何直接的高字节,仅包含 % 编码的相同版本,因此即使有 charset 参数也不会受到影响。 同时multipart子部分的头部内容不受RFC2616影响,但受普通MIME头部规则的影响;应该可以根据 RFC2388(定义 multipart/form-data)为子部分指定编码,但没有浏览器这样做,很少有服务器会费心寻找它。 (如果你尝试,奇怪的会坏掉,这就是为什么没有浏览器添加对它的支持。)

以上是关于如何强制浏览器在内容类型 http 标头中设置字符集的主要内容,如果未能解决你的问题,请参考以下文章

如何在HTTP响应中设置标头?

如何在http get请求中设置标头?

如何在 Apache JClouds 中设置 HTTP 标头?

如何在HTTP标头中设置REMOTE_USER?

如何在Gitlab中设置HTTP缓存标头?

无法在 Fetch Get 请求中设置任何标头