Node.js和UTF-8在POST数据中的应用

8

我在使用Node.JS web服务器时,遇到了解码POST数据中UTF-8字符串的问题。

请查看以下完整测试用例:

require("http").createServer(function(request, response) {

  if (request.method != "POST") {

    response.writeHead(200, {'Content-Type': 'text/html; charset=utf-8'});
    response.end('<html>'+
      '<head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head>'+
      '<body>'+
      '<form method="post">'+
      '<input name="test" value="Grüße!"><input type="submit">'+
      '</form></body></html>');

  } else {

    console.log("CONTENT TYPE=",request.headers['content-type']);

    var body="";
    request.on('data', function (data) {
      body += data;
    });

    request.on('end', function () {
      console.log("POST BODY=",body);

      response.writeHead(200, {'Content-Type': 'text/plain; charset=utf-8'});
      response.end("POST DATA:\n"+body+"\n---\nUNESCAPED:\n"+unescape(body)+
        "\n---\nHARDCODED: Grüße!");
    });

  }

}).listen(11180);

这是一个独立的Web服务器,它监听11180端口,并发送包含输入字段和特殊字符的简单表单的HTML页面。将该表单POST到服务器将在纯文本响应中回显其内容。
我的问题是特殊字符无法正确显示,无论是在控制台还是浏览器中都是如此。这是我在FireFox和IE中看到的内容:
POST DATA:
test=Gr%C3%BC%C3%9Fe%21
---
UNESCAPED:
test=GrüÃe!
---
HARDCODED: Grüße!

最后一行是一个硬编码的字符串Grüße!,应该与输入字段的值匹配(以验证它不是显示问题)。显然,POST数据没有被解释为UTF-8。使用require('querystring')将数据分解成字段时也会出现同样的问题。
有什么线索吗?
在Debian Linux 4上使用Node.JS v0.4.11,源代码保存在utf-8字符集中。

好的,我可以部分回答自己的问题:使用decodeURIComponent()而不是unescape()可以解决核心问题。然而,这意味着querytring Node.JS模块完全无用,我必须自己进行解析。或者我错过了什么? - Udo G
1个回答

6

üß UTF-8字符不在ASCII字符集中,因此将由多个ASCII字符表示。

根据http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1

内容类型“application/x-www-form-urlencoded”在发送大量二进制数据或包含非ASCII字符的文本时效率低下。应该使用内容类型“multipart/form-data”提交包含文件、非ASCII数据和二进制数据的表单。

将表单上的enctype切换为multipart <form method="post" enctype="multipart/form-data /> 将正确呈现UTF-8字符。然后您需要解析multipart格式。似乎node-formidable是最受欢迎的库。

如您在评论中提到的,使用decodeURIComponent()可能会更简单。Unescape无法处理多字节字符,而是将每个字节表示为自己的字符,因此出现了混淆。可以参考http://xkr.us/articles/javascript/encode-compare/

您还可以使用缓冲区来更改编码。在这种情况下有些过度,但如果需要,可以使用:

new Buffer(myString, 'ascii').toString('utf8');

我应该把这个答案贴在我的墙上。 - simo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接