Скрипт, имеющий проблемы с передачей Юникода через интерфейс REST - PullRequest
1 голос
/ 24 мая 2011

У меня проблемы с получением сценария Python для передачи данных Unicode через вызов RESTful http.

У меня есть скрипт, который считывает данные с веб-сайта X с использованием интерфейса REST, а затем помещает их на веб-сайт Y с помощью интерфейса REST. Обе системы с открытым исходным кодом и работают на наших серверах. Сайт X использует PHP, Apache и PostgreSQL. Сайт Y - это Java, Tomcat и PostgreSQL. Сценарий, выполняющий обработку, в настоящее время находится на Python.

В общем, скрипт работает очень хорошо. У нас действительно есть несколько международных пользователей, и при попытке обработать пользователя с символами юникода в его имени вещи ломаются. Оригинальная версия скрипта считывает данные JSON в Python. Данные были автоматически преобразованы в Unicode. Я почти уверен, что до этого момента все работало нормально. Для вывода данных я использовал subprocess.Popen () для вызова curl. Это работает для обычной ASCII, но Unicode был искажен где-то в пути. Я нигде не получил сообщение об ошибке, но при просмотре результатов на сайте B оно больше не корректно закодировано.

Я знаю, что Unicode поддерживается для этих полей, потому что я могу обработать запрос, используя Firefox, который правильно добавляет данные на сайт B.

Следующей идеей было не использовать curl, а просто делать все на Python. Я экспериментировал, передавая вручную созданную строку Unicode в urllib Python, чтобы сделать вызов 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 Ответ

2 голосов
/ 24 мая 2011

Что касается вашего тестового скрипта, он терпит неудачу, потому что вы передаете объект Unicode в urllib.urlencode() (он вызывается для вас urlopen()). Он не поддерживает объекты Unicode, поэтому он неявно кодирует, используя набор символов по умолчанию, который равен ascii. Очевидно, что это не удается.

Самый простой способ обработки объектов Unicode POST - это явный; Соберите свои данные и создайте dict, кодируйте значения Unicode с помощью соответствующего набора символов, urlencode dict (чтобы получить 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)

РЕДАКТИРОВАТЬ: В целом, когда вы делаете HTTP-запрос с Python (скажем, urllib2.urlopen), содержание ответа не декодировано для Unicode для вас. Это означает, что вам нужно знать о кодировке, используемой сервером, который его отправил. Посмотрите на заголовок content-type; Обычно это включает charset=xyz.

Всегда целесообразно декодировать входные данные как можно раньше и кодировать выходные данные как можно позже.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...