繁体   English   中英

使用node.js编码错误

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM