脚本无法通过REST接口传递Unicode

时间:2011-05-24 14:41:08

标签: python rest unicode

我无法让我的Python脚本通过RESTful http调用来识别Unicode数据。

我有一个脚本,使用REST接口从网站X读取数据,然后使用它的REST接口将其推送到网站Y.两个系统都是开源的,并在我们的服务器上运行。 Site X使用PHP,Apache和PostgreSQL。站点Y是Java,Tomcat和PostgreSQL。执行处理的脚本目前在Python中。

通常,脚本运行良好。我们确实有一些国际用户,在尝试处理名字中包含unicode字符的用户时,事情会发生故障。脚本的原始版本将JSON数据读入Python。数据自动转换为Unicode。我很确定到目前为止一切正常。为了输出数据,我使用subprocess.Popen()来调用curl。这适用于常规的ascii,但unicode在运输过程中的某个地方被破坏了。我没有在任何地方收到错误,但在网站B上查看结果时,它不再正确编码。

我知道这些字段支持Unicode,因为我可以使用Firefox正确地将数据添加到站点B来创建请求。

接下来的想法是不使用curl,而只是用Python做一切。我通过将一个手构造的Unicode字符串传递给Python的urllib来进行实验,以进行REST调用,但是我收到了来自urllib.urlopen()的错误: UnicodeEncodeError: 'ascii' codec can't encode characters in position 103-105: ordinal not in range(128)

有关如何使这项工作的任何想法?我宁愿不重写太多,但如果有另一种更适合的脚本语言,我也不介意听到这个。

这是我的Python测试脚本:

import urllib

uni = u"abc_\u03a0\u03a3\u03a9"

post = u"xdat%3Auser.login=unitest&"
post += u"xdat%3Auser.primary_password=nauihe4r93nf83jshhd83&"
post += u"xdat%3Auser.firstname=" + uni + "&"
post += u"xdat%3Auser.lastname=" + uni ;

url = u"http://localhost:8081/xnat/app/action/XDATRegisterUser"

data = urllib.urlopen(url,post).read()

1 个答案:

答案 0 :(得分:2)

关于您的测试脚本,它失败了,因为您正在将unicode对象传递给urllib.urlencode()urlopen()正在为您调用它)。它不支持unicode对象,因此它使用默认字符集隐式编码,即ascii。显然,它失败了。

处理POST unicode对象的最简单方法是显式;收集数据并构建一个dict,使用适当的字符集对unicode值进行编码,对dict进行urlencode(获取POSTable ascii字符串),然后启动请求。您的示例可以重写为:

import urllib
import urllib2

## Build our post data dict
data = {
    'xdat:user.login' : u'unitest', 
    'xdat:primary_password' : u'nauihe4r93nf83jshhd83', 
    'xdat:firstname' : u"abc_\u03a0\u03a3\u03a9", 
    'xdat:lastname' : u"abc_\u03a0\u03a3\u03a9", 
}

## Encode the unicode using an appropriate charset
data = dict([(key, value.encode('utf8')) for key, value in data.iteritems()])

## Urlencode it for POSTing
data = urllib.urlencode(data)

## Build a POST request, get the response
url = "http://localhost:8081/xnat/app/action/XDATRegisterUser"
request = urllib2.Request(url, data)
response = urllib2.urlopen(request)

编辑:更一般地说,当您使用python发出http请求时(比如urllib2.urlopen), 响应的内容为您解码为unicode。这意味着您需要了解发送它的服务器所使用的编码。查看content-type标题;通常它包含charset=xyz

尽可能早地解码您的输入,并尽可能晚地对输出进行编码。