UnicodeDecodeError возникает при получении файла cookie в Google App Engine - PullRequest
2 голосов
/ 27 июля 2011

У меня есть проект GAE в Python, где я устанавливаю cookie в одном из моих RequestHandlers с этим кодом:

self.response.headers['Set-Cookie'] = 'app=ABCD; expires=Fri, 31-Dec-2020 23:59:59 GMT'

Я зарегистрировался в Chrome и вижу список файлов cookie, поэтому он работает.

Затем, позже, в другом RequestHandler, я получаю cookie для проверки:

appCookie = self.request.cookies['app']

Эта строка выдает следующую ошибку при выполнении:

UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 1962: ordinal not in range(128)

Похоже, что он пытается декодировать информацию о входящем куки, используя кодек ASCII, а не UTF-8.

Как заставить Python использовать UTF-8 для декодирования этого?

Существуют ли какие-либо другие ошибки, связанные с Unicode, о которых мне нужно знать как новичку в Python и Google App Engine (но опытный программист на других языках)?

Вот полный Traceback:

Traceback (most recent call last):
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/tools/dev_appserver.py", line 4144, in _HandleRequest
    self._Dispatch(dispatcher, self.rfile, outfile, env_dict)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/tools/dev_appserver.py", line 4049, in _Dispatch
    base_env_dict=env_dict)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/tools/dev_appserver.py", line 616, in Dispatch
    base_env_dict=base_env_dict)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/tools/dev_appserver.py", line 3120, in Dispatch
    self._module_dict)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/tools/dev_appserver.py", line 3024, in ExecuteCGI
    reset_modules = exec_script(handler_path, cgi_path, hook)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/tools/dev_appserver.py", line 2887, in ExecuteOrImportScript
    exec module_code in script_module.__dict__
  File "/Users/ken/hgdev/juicekit/main.py", line 402, in <module>
    main()
  File "/Users/ken/hgdev/juicekit/main.py", line 399, in main
    run_wsgi_app(application)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/ext/webapp/util.py", line 98, in run_wsgi_app
    run_bare_wsgi_app(add_wsgi_middleware(application))
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/ext/webapp/util.py", line 116, in run_bare_wsgi_app
    result = application(env, _start_response)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/ext/webapp/__init__.py", line 721, in __call__
    response.wsgi_write(start_response)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/ext/webapp/__init__.py", line 296, in wsgi_write
    body = self.out.getvalue()
  File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/StringIO.py", line 270, in getvalue
    self.buf += ''.join(self.buflist)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 1962: ordinal not in range(128)

Ответы [ 2 ]

0 голосов
/ 07 августа 2011

Во-первых, закодируйте любое значение Юникода, установленное вами в файлах cookie.Вам также нужно заключить их в кавычки на случай, если они могут сломать заголовок:

import urllib

# This is the value we want to set.
initial_value = u'äëïöü'
# WebOb version that comes with SDK doesn't quote cookie values
# in the Response, neither webapp.Response. So we have to do it.
quoted_value = urllib.quote(initial_value.encode('utf-8'))

rsp = webapp.Response()
rsp.headers['Set-Cookie'] = 'app=%s; Path=/' % quoted_value

Теперь давайте прочитаем значение.Чтобы проверить это, создайте подделку Request, чтобы проверить установленный нами файл cookie.Этот код был извлечен из реального юнит-теста:

cookie = rsp.headers.get('Set-Cookie')
req = webapp.Request.blank('/', headers=[('Cookie', cookie)])

# The stored value is the same quoted value from before.
# Notice that here we use .str_cookies, not .cookies.
stored_value = req.str_cookies.get('app')
self.assertEqual(stored_value, quoted_value)

Наше значение все еще закодировано и заключено в кавычки.Мы должны сделать обратное, чтобы получить начальный:

# And we can get the initial value unquoting and decoding.
final_value = urllib.unquote(stored_value).decode('utf-8')
self.assertEqual(final_value, initial_value)

Если вы можете, рассмотрите возможность использования webapp2 .webob.Response выполняет всю тяжелую работу по цитированию и настройке файлов cookie, и вы можете напрямую устанавливать значения Юникода.См. Краткое изложение этих проблем здесь .

0 голосов
/ 27 июля 2011

Вы собираетесь использовать функцию decode примерно так (cred @agf:):

self.request.cookies['app'].decode('utf-8')

Из официальной документации Python (плюс пара добавленных деталей):

8-битные строки Python имеют метод .decode ([encoding], [errors]), который интерпретирует строку с использованием заданной кодировки. В следующем примере показано, как строка переходит в юникод, а затем возвращается к 8-битной строке:

>>> u = unichr(40960) + u'abcd' + unichr(1972)   # Assemble a string
>>> type(u), u                                   # Examine
(<type 'unicode'>, u'\ua000abcd\u07b4')
>>> utf8_version = u.encode('utf-8')             # Encode as UTF-8
>>> type(utf8_version), utf8_version             # Examine
(<type 'str'>, '\xea\x80\x80abcd\xde\xb4')
>>> u2 = utf8_version.decode('utf-8')            # Decode using UTF-8
>>> u == u2                                      # The two strings match
True
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...