Java中的HTTP头编码/解码

ebr*_*hez 13 java servlets header http utf-8

正在将自定义HTTP标头传递给Servlet应用程序以进行身份​​验证.标头值必须能够包含重音和其他非ASCII字符,因此必须采用特定编码(理想情况下为UTF-8).

控制身份验证环境的开发人员向我提供了这段Java代码:

String firstName = request.getHeader("my-custom-header"); 
String decodedFirstName = new String(firstName.getBytes(),"UTF-8");
Run Code Online (Sandbox Code Playgroud)

但是这段代码对我来说看起来并不合适:它假定了头值的编码,当我觉得有一种正确的方法来指定头值的编码时(我认为来自MIME).

这是我的问题:处理需要支持UTF-8编码的自定义标头值的正确方法(tm)是什么:

  • 在电线上(标题在电线上的样子)
  • 从解码的角度来看(如何使用Java Servlet API对其进行解码,我们可以假设request.getHeader()已经正确地进行了解码)

这是一个与环境无关的代码示例,如果您无法更改服务,则将标头视为UTF-8:

String valueAsISO = request.getHeader("my-custom-header"); 
String valueAsUTF8 = new String(firstName.getBytes("ISO8859-1"),"UTF-8");
Run Code Online (Sandbox Code Playgroud)

小智 7

再说一次:RFC 2047在实践中没有实现.HTTP/1.1的下一个版本将删除任何提及它.

因此,如果您需要传输非ASCII字符,最安全的方法是将它们编码为ASCII序列,例如Atom发布协议中的"Slug"标头.

  • 但是,如果自定义HTTP标头的编码选择是特定于实现的,则选择RFC 2047编码与任何其他编码(例如您提到的Atom中的编码)一样有效.所以没有理由*不*使用RFC 2047编码. (2认同)

mko*_*ler 5

正如已经提到的,首先应该查看HTTP 1.1 规范(RFC 2616)。它表示,如果标头值中的文本包含来自除 ISO-8859-1 以外的字符集的字符,则它必须使用定义为RFC 2047的 MIME 编码。

所以这对你来说是一个加分项。如果 ISO-8859-1 字符集涵盖了您的要求,那么您只需将您的字符放入请求/响应消息中。否则 MIME 编码是唯一的选择。

只要用户代理根据这些规则将值发送到您的自定义标头,您就不必担心解码它们。这就是 Servlet API 应该做的。


但是,还有一个更基本的原因,为什么您的代码片段没有按预期执行。第一行以 Java 字符串的形式获取标头值。正如我们所知,它在内部表示为 UTF8,因此此时 HTTP 请求消息解析已经完成并完成。

下一行获取该字符串的字节数组。由于没有指定编码(恕我直言,这种没有参数的方法早就应该被弃用),因此使用当前系统默认编码,通常不是 UTF8,然后数组再次转换为 UTF8 编码。输出。

  • 一个小更正:Java 字符串在内部根本不表示为 UTF-8。表示接近 UCS-2(类似于 UTF-16)。出于所有实际目的,编码/解码仅在将 Java 字符串转换为外部表示时才重要。 (3认同)

Jul*_*hke 5

HTTPbis工作组知道这个问题,并且最新的草案摆脱了与TEXT和RFC 2047编码相关的所有语言 - 它实际上并未在HTTP上使用.

有关整个故事,请参见http://trac.tools.ietf.org/wg/httpbis/trac/ticket/74.


sup*_*ell 4

规则请参见HTTP 规范,第 2.2 节中有说明

TEXT 规则仅用于不打算由消息解析器解释的描述性字段内容和值。仅当根据 RFC 2047 [14] 的规则进行编码时, *TEXT 的单词才可以包含 ISO-8859-1 [22] 以外的字符集中的字符。

上面的代码不会正确解码 RFC2047 编码字符串,让我相信该服务没有正确遵循规范,它们只是在标头中嵌入原始 utf-8 数据。