Flask - заголовки не конвертируются в юникод?

Я разрабатываю небольшой веб-сервис на python, используя:

  • Колба (v. 0.8)
  • шторм ORM (v. 0.19)
  • Апач с mod_wsgi

У меня есть собственный HTTP-заголовок Unison-UUID, который я использую в какой-то момент для получения информации из моей базы данных.

вот (слегка переписанный для простоты) фрагмент, с которым у меня возникли проблемы:

uuid = flask.request.headers['Unison-UUID']
store = storm.locals.Store(my_database)
user = store.get(models.User, uuid)

Класс User примерно такой:

class User(Storm):
    uuid = Unicode(primary=True)
    # Other columns....

Приведенный выше код терпит неудачу следующим образом:

  File "/Users/lum/Documents/unison-recsys/www/api/unison/unison.py", line 27, in decorated
    user = g.store.get(models.User, uuid)
  File "/Users/lum/Documents/unison-recsys/venv/lib/python2.6/site-packages/storm/store.py", line 165, in get
    variable = column.variable_factory(value=variable)
  File "/Users/lum/Documents/unison-recsys/venv/lib/python2.6/site-packages/storm/variables.py", line 396, in parse_set
    % (type(value), value))
TypeError: Expected unicode, found <type 'str'>: '00000000-0000-0000-0000-000000000009'

Я не очень понимаю, почему это происходит и что я могу с этим поделать. Я думал, что Flask на 100 % состоит из юникода.

Быстрое исправление, которое я нашел, состоит в том, чтобы декодировать значение заголовка, то есть uuid = uuid.decode('utf-8'). Это действительно то, что нужно сделать? Это кажется немного хакерским. Нет ли способа получить юникод напрямую, без необходимости «декодировать» его вручную?


person lum    schedule 12.04.2012    source источник
comment
Может представлять интерес: stackoverflow.com/q/818122/311220 stackoverflow.com/q/7567154/311220   -  person Acorn    schedule 12.04.2012


Ответы (2)


На http://flask.pocoo.org/docs/api/#flask.request мы читаем

Объект запроса является экземпляром подкласса Request и предоставляет все атрибуты, определенные Werkzeug.

Слово Request ссылается на http://werkzeug.pocoo.org/docs/wrappers/#werkzeug.wrappers.Request, где мы читаем

Классы Request и Response являются подклассами классов BaseRequest и BaseResponse и реализуют все миксины, которые предоставляет Werkzeug:

Слово BaseRequest ссылается на http://werkzeug.pocoo.org/docs/wrappers/#werkzeug.wrappers.BaseRequest, где мы читаем

headers
Заголовки из среды WSGI как неизменяемые EnvironHeaders.

Слово EnvironHeaders ссылается на http://werkzeug.pocoo.org/docs/datastructures/#werkzeug.datastructures.EnvironHeaders, где мы читаем

Он предоставляет тот же интерфейс, что и Заголовки, и создается в среде WSGI.

Слово Заголовки... нет, оно не связано, но оно должно было быть связано с http://werkzeug.pocoo.org/docs/datastructures/#werkzeug.datastructures.Заголовки, где мы читаем

Заголовки в основном совместимы с классом Python wsgiref.headers.Headers.

где фраза wsgiref.headers.Headers ссылается на http://docs.python.org/dev/library/wsgiref.html#wsgiref.headers.Headers, где мы читаем

Создайте заголовки-обертки объектов, подобные сопоставлению, которые должны быть списком кортежей имени/значения заголовка, как описано в PEP 3333.

Фраза PEP 3333 ссылается на http://www.python.org/dev/peps/pep-3333/, где нет явного определения того, какой тип заголовков должен быть, но после некоторого поиска по слову headers мы находим это утверждение

Поэтому WSGI определяет два типа «строки»:

"Native" strings (which are always implemented using the type named str)
that are used for request/response headers and metadata
"Bytestrings" (which are implemented using the `bytes` type in Python 3,
and `str` elsewhere), that are used for the bodies of requests and
responses (e.g. POST/PUT input data and HTML page outputs).

Вот почему в Python 2 вы получаете заголовки как str, а не unicode.

Теперь приступим к расшифровке.

Ни ваш .decode('utf-8'), ни .decode('ascii') Менси (и слепое ожидание какой-либо другой кодировки) не являются универсально хорошими, потому что теоретически значения полей заголовка HTTP могут передавать что угодно; сложная часть состоит в том, чтобы заставить все стороны (отправителя, получателя и посредников) согласовать кодировку.. Сказав, что я думаю, вы должны действовать в соответствии с советом Джулиана Решке.

Таким образом, безопасный способ сделать это - придерживаться ASCII и выбрать кодировку поверх нее, например ту, что определена в RFC 5987.

после проверки того, что пользовательские агенты (браузеры), которые вы поддерживаете, внедрили его.

Заголовок RFC 5987: Набор символов и кодировка языка для протокола передачи гипертекста (HTTP). Параметры поля заголовка

person Piotr Dobrogost    schedule 12.04.2012

Значения заголовка - ASCII, см. связанные вопросы от Acorn.

Что вы можете сделать здесь, так это либо декодировать его вручную, как вы это делали (хотя вы должны использовать uuid.decode('ascii'), а не utf-8), либо изменить свое поле на RawStr вместо Unicode

person mensi    schedule 12.04.2012
comment
Спасибо за упоминание RawStr. Это действительно может быть лучшим выбором в моем конкретном случае. - person lum; 13.04.2012