[英]Encoding error with node.js
我正在重写node.js中的一个小python脚本。 原始脚本的工作方式如下:
# -*- coding: utf-8 -*-
import urllib
import httplib
import json
def rpc(url, args = { }):
try:
post_data = json.dumps({'args': args})
f = urllib.urlopen(url, post_data)
if not f or f.code != 200:
return { 'result': 1, 'error': 'urlopen returned error' }
data = f.read()
js_data = json.loads(data)
except Exception, e:
return { 'result': 2, 'error': e }
else:
return { 'result': 0, 'data': js_data }
print rpc('http://server.local/rpc', {'x': u'тест'})
我在node.js中使用request来做同样的事情:
var request = require('request')
request.post('http://server.local/rpc', {
json: {'x': 'тест'}
}, function(err, result) {
console.log(err, result.body)
})
它工作正常,但是unicode数据是乱码的,因此在查询数据时我得到了ÑеÑÑ
而不是тест
。 考虑到python和node.js都应该发送utf8编码数据,这似乎很奇怪。
顺便说一句,我认为服务器是用perl编写的,但这就是我所知道的:(
此外,服务器会返回其他查询Unicode数据,所以它能够做到这一点。
UPD。 我的控制台打印unicode字符很好。
UPD。 重写我的代码以使用node.js http
模块:
var http = require('http')
var options = {
hostname : 'server.local',
path : '/rpc',
method : 'POST'
}
var req = http.request(options, function (res) {
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log('BODY: ' + chunk);
});
});
var body = JSON.stringify({'x': 'тест'})
req.setHeader('Content-length', body.length)
// python sends data with this header
req.setHeader('Content-type', 'application/x-www-form-urlencoded')
req.on('error', function (e) {
console.log('problem with request: ' + e);
});
req.end(body, 'utf8');
结果遗憾地相同。 在两个不同的安装(我的个人MBA和生产Debian服务器)上也有相同的行为。 所以它似乎与node.js表示unicode数据的方式有关。
这是python脚本的请求:
POST / HTTP/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 43
Host: localhost:1234
User-Agent: Python-urllib/1.17
{"args": {"x": "\u0442\u0435\u0441\u0442"}}
以下是node.js服务器发出的请求:
POST /rpc HTTP/1.1
Host: localhost:1234
Content-length: 12
Content-type: application/x-www-form-urlencoded
Connection: keep-alive
{"x":"тест"}
你看到了问题吗? JSON.stringify将数据编码为utf8字符串,但python将其编码为ascii。
如果您的rpc服务器不理解utf8,您可以使用外部库对json进行编码。 例如,这可以工作:
var request = require('request');
var jju = require('jju');
request.post({
uri: 'http://localhost:8080/rpc',
body: jju.stringify({args: {x: "тест"}}, {
mode: 'json',
indent: false,
ascii: true,
}),
}, function(err, res, body) {
console.log(body);
});
使用上面的代码,请求将如下所示:
POST /rpc HTTP/1.1
host: localhost:8080
content-length: 41
Connection: keep-alive
{"args":{"x":"\u0442\u0435\u0441\u0442"}}
这与python正在做的类似。
好吧,尝试消除变量。
使用原生的http.request而不是request
模块,即使它更复杂,它也会消除request
作为可能的罪魁祸首。
发送数据时,请明确显示utf8
编码 。
我不太了解request
模块的内部,以确定可能发生故障的位置或者是否需要传递选项,但这至少可以让您找出默认节点http.request
可能会让您失败,或者您的安装似乎存在更深层次的问题。
真正的问题是,您告诉服务器您要发送的数据少于实际发送的数据。 因此,当服务器尝试编码数据时,它会被破坏。
body.length为您提供字符串主体中“元素”的数量。 对于US-ASCII字符,1个元素= 1个字节,但这不适用于非US-ASCII字符。
每次使用非US-ASCII时,使用已使用的逻辑,您将添加一个字节超重,您应该为Content-length标头计算。
http://en.wikipedia.org/wiki/UTF-8
将第15行更改为:
var utf8overLoad = encodeURIComponent(body).match(/%[89ABab]/g).length || 0;
var bodylength = body.length + utf8overLoad ;
req.setHeader('Content-length', bodylength);
我认为这可能来自您的服务器或控制台。
我刚刚在一个具有urt8容量的控制台(字体'Lucida Console')中测试了nodeJS中的客户端和服务器写入,并且它可以工作。 服务器代码:
var express = require('express');
var app = express()
.use(express.methodOverride())
.use(express.bodyParser())
.post('/rpc', function(req, res) {
console.log(JSON.stringify(req.body, null, 2));
res.send(req.body.x);
};
app.listen(8080);
(使用express@3.4.8)
控制台输出请求:
{
"x": "тест"
}
客户代码:
var request = require('request');
request.post({
uri:'http://localhost:8080/rpc',
json:{"x": "тест"}
}, function(err, res, body) {
console.log(body);
});
(使用request@2.21.0)
控制台输出:
тест
NodeJS 0.10.4的整体操作
它也可以使用像curl这样的HTTP客户端或“高级REST客户端”chrome扩展。
但重要的是请求是使用“application / json”编码(不是经典的x-www-form-urlencoded)发送的,并且服务器上的bodyParser()
中间件执行JSON反序列化。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.