【问题标题】:Node.js not using ISO-8859-1 encoding for HTTP response headersNode.js 未对 HTTP 响应标头使用 ISO-8859-1 编码
【发布时间】:2014-11-09 23:49:41
【问题描述】:

我有一个 HTTP 响应标头,其中包含 ISO-8859-1 字符(é0x39)。下面是显示 HTTP 响应的原始数据包捕获,底部第二行:

00000000  48 54 54 50 2f 31 2e 30  20 32 30 30 20 4f 4b 0d HTTP/1.0  200 OK.
00000010  0a 43 6f 6e 74 65 6e 74  2d 54 79 70 65 3a 20 61 .Content -Type: a
00000020  75 64 69 6f 2f 61 61 63  70 0d 0a 69 63 79 2d 62 udio/aac p..icy-b
00000030  72 3a 34 30 0d 0a 69 63  79 2d 67 65 6e 72 65 3a r:40..ic y-genre:
00000040  4a 61 7a 7a 20 4c 6f 75  6e 67 65 20 43 61 66 65 Jazz Lou nge Cafe
00000050  0d 0a 69 63 79 2d 6e 61  6d 65 3a 43 61 66 e9 20 ..icy-na me:Caf. 
00000060  64 65 20 50 61 72 69 73  20 2d 20 52 41 44 49 4f de Paris  - RADIO

标题应该是:

icy-name:Café de Paris

我正在做一个非常简单的http.get() 请求:

http.get('http://example.com/streamUrl', function (res) {
    console.log(res.headers);
});

在我的控制台上,我看到:

'icy-name': 'Caf� de Paris',

然后我尝试将字符串转换为缓冲区:

console.log(new Buffer(res.headers['icy-name']));
// <Buffer 43 61 66 ef bf bd 20 64 65 20 50 61 72 69 73 ... >

原来的字符0xe9似乎在转换到我的Buffer之前或者在转换过程中已经丢失了。然后,我认为iconv-lite 可能会有所帮助:

var iconv = require('iconv-lite');
iconv.extendNodeEncodings();
console.log( (new Buffer(res.headers['icy-name'], 'latin1')).toString('utf8') );
// "Caf? de Paris" with a literal question mark, `0x3F`.

我怀疑在我的代码获得响应标头值之前损坏已经造成。我的问题:

  1. 我的假设是否正确,即字符串首先被 Node.js 的 HTTP 客户端错误解释?
  2. 是否可以配置 Node.js 以正确处理 HTTP 响应? RFC5987 表示 HTTP 响应的默认字符集是 ISO-8859-1。
  3. 如果没有办法让 Node.js 正常运行,有没有办法撤消转换损坏,恢复原始 ISO-88591-1 字符串,然后转换为 UTF-8?

【问题讨论】:

  • 而且您确定所有文件都保存为 UFT8 等。
  • @adeneo 它与文件没有任何关系。我说的是 HTTP 响应标头本身。此响应中的实际数据是二进制的,无需担心。其他 HTTP 客户端已经能够成功处理响应标头。此外,有问题的数据是 ISO-88591-1,而不是 UTF-8。我需要转换为 UTF-8,但我感觉 ISO-88591-1 字符串一开始就没有正确处理。
  • @adeneo 我什么都没设置。我的 Node.js 代码是客户端,而不是服务器。我正在访问其他服务器上的标头,这不是我的代码,也不是用 Node.js 构建的。即使是这样,标准(据我所知)规定 HTTP 响应标头默认情况下应为 ISO-8895-1。您可以从十六进制转储中看到响应数据在通过网络发送时很好。我也知道其他 HTTP 客户端可以正确处理响应标头。数据的来源不是问题。问题与 Node.js 或我的应用程序有关。

标签: javascript node.js http character-encoding http-headers


【解决方案1】:

不幸的是,据我所知,没有官方规范已被广泛实施以在 HTTP 标头中传输非 ACSII 数据。您链接到的 RFC 仅处于 PROPOSED STANDARD 状态,并且是从 2010 年开始的。看起来节点 0.10 基本上将标头值显式传递给 new String(val),因此这些值被解析为 utf8 值。看起来在 Node 0.11 中,字符串并没有那么混乱,所以

var iconv = new Iconv('ISO-8859-1', 'UTF-8');
console.log(iconv.convert(new Buffer(res.headers['icy-name'], 'binary')));

0.11 中确实如您所期望的那样工作。我不能肯定这是故意的,还是只是其他工作的副作用。

【讨论】:

  • 感谢您的来信。我链接到的 RFC 中唯一相关的部分是摘要。它没有具体提到 where 有一个规范说在标头中允许使用 ISO-8891-1 字符。我并不是要暗示 RFC5987 本身就是标准。无论如何,我最终在 Node.js 的 GitHub 问题跟踪器上发布了这个问题:github.com/joyent/node/issues/8699#issuecomment-62342294 在那里确认该问题是 Node.js v0.10 中使用的 V8 的限制,并且它已在v0.11 及更高版本。
【解决方案2】:

FWIW 我刚刚写了一个可用的 Http.Agent here,它将把头数据从 latin1 解码为 utf8,它会覆盖原来的头。

【讨论】:

    猜你喜欢
    • 2011-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-12
    • 1970-01-01
    • 2018-02-21
    • 2012-02-17
    • 1970-01-01
    相关资源
    最近更新 更多