Если вы пытаетесь построить ключ с недопустимым параметром urlsafe
key = ndb.Key(urlsafe='bogus123')
вы получите ошибку, как
Traceback (most recent call last):
File "/opt/google/google_appengine/google/appengine/runtime/wsgi.py", line 240, in Handle
handler = _config_handle.add_wsgi_middleware(self._LoadHandler())
File "/opt/google/google_appengine/google/appengine/runtime/wsgi.py", line 299, in _LoadHandler
handler, path, err = LoadObject(self._handler)
File "/opt/google/google_appengine/google/appengine/runtime/wsgi.py", line 85, in LoadObject
obj = __import__(path[0])
File "/home/tim/git/teledap-appengine/main.py", line 10, in <module>
from src.tim import handlers as handlers_
File "/home/tim/git/teledap-appengine/src/tim/handlers.py", line 42, in <module>
class ResetHandler(BaseHandler):
File "/home/tim/git/teledap-appengine/src/tim/handlers.py", line 47, in ResetHandler
key = ndb.Key(urlsafe='bogus123')
File "/opt/google/google_appengine/google/appengine/ext/ndb/key.py", line 212, in __new__
self.__reference = _ConstructReference(cls, **kwargs)
File "/opt/google/google_appengine/google/appengine/ext/ndb/utils.py", line 142, in positional_wrapper
return wrapped(*args, **kwds)
File "/opt/google/google_appengine/google/appengine/ext/ndb/key.py", line 642, in _ConstructReference
reference = _ReferenceFromSerialized(serialized)
File "/opt/google/google_appengine/google/appengine/ext/ndb/key.py", line 773, in _ReferenceFromSerialized
return entity_pb.Reference(serialized)
File "/opt/google/google_appengine/google/appengine/datastore/entity_pb.py", line 1710, in __init__
if contents is not None: self.MergeFromString(contents)
File "/opt/google/google_appengine/google/net/proto/ProtocolBuffer.py", line 152, in MergeFromString
self.MergePartialFromString(s)
File "/opt/google/google_appengine/google/net/proto/ProtocolBuffer.py", line 168, in MergePartialFromString
self.TryMerge(d)
File "/opt/google/google_appengine/google/appengine/datastore/entity_pb.py", line 1839, in TryMerge
d.skipData(tt)
File "/opt/google/google_appengine/google/net/proto/ProtocolBuffer.py", line 677, in skipData
raise ProtocolBufferDecodeError, "corrupted"
ProtocolBufferDecodeError: corrupted
Интересно здесь находятся вне
File "/opt/google/google_appengine/google/appengine/ext/ndb/key.py", line 773, in _ReferenceFromSerialized
return entity_pb.Reference(serialized)
, который является последний код, выполненный в key.py module:
def _ReferenceFromSerialized(serialized):
"""Construct a Reference from a serialized Reference."""
if not isinstance(serialized, basestring):
raise TypeError('serialized must be a string; received %r' % serialized)
elif isinstance(serialized, unicode):
serialized = serialized.encode('utf8')
return entity_pb.Reference(serialized)
serialized
здесь, будучи расшифрованной строкой urlsafe, вы можете прочитать об этом по ссылке на исходный код.
еще один интересный один последний один:
File "/opt/google/google_appengine/google/appengine/datastore/entity_pb.py", line 1839, in TryMerge
в entity_pb.py module, который выглядит как этот
def TryMerge(self, d):
while d.avail() > 0:
tt = d.getVarInt32()
if tt == 106:
self.set_app(d.getPrefixedString())
continue
if tt == 114:
length = d.getVarInt32()
tmp = ProtocolBuffer.Decoder(d.buffer(), d.pos(), d.pos() + length)
d.skip(length)
self.mutable_path().TryMerge(tmp)
continue
if tt == 162:
self.set_name_space(d.getPrefixedString())
continue
if (tt == 0): raise ProtocolBuffer.ProtocolBufferDecodeError
d.skipData(tt)
который где фактическая попытка «слить вклад в Key» является сделал.
Вы можете увидеть в исходном коде, что в процессе построения ключа от параметра urlsafe не много может пойти не так. Сначала он проверяет, является ли вход строкой, а если нет, то TypeError
поднят, если он есть, но он не является «действительным», действительно поднят ProtocolBufferDecodeError
.
Мой текущий эксперимент показывает, что оператор будет бросать ProtocolBufferDecodeError (Невозможно слить из строки.) Исключение, если some_user_input является недействительным, но не смог найти ничего об этом от API. Может кто-то прокомментировать это?
Подтвержденный - мы теперь знаем, что также может быть поднят TypeError.
и указать мне лучший способ проверки правильности ввода пользователем вместо того, чтобы ловить исключение?
Это отличный способ проверить правильность!Почему сами чеки, если они уже сделаны appengine? Фрагмент кода может выглядеть так (не рабочий код, просто пример)
def get(self):
# first, fetch the user_input from somewhere
try:
key = ndb.Key(urlsafe=user_input)
except TypeError:
return 'Sorry, only string is allowed as urlsafe input'
except ProtocolBufferDecodeError:
return 'Sorry, the urlsafe string seems to be invalid'
Большое спасибо за ваш ответ и все указатели на исходный код @Tim! Теперь все имеет смысл. Единственное, что меня сейчас немного волнует, - это «ПротоколBufferDecodeError», который не публикован. Я боюсь, что это будет означать использование не документированного API, и Google может изменить эти внутренние функции, например. тип исключения, в будущем без нарушения контракта спецификации. –
@YingXiong его реализация [здесь] (https://code.google.com/p/googleappengine/source/browse/trunk/python/google/net/proto/ProtocolBuffer.py), и это довольно широко используется в appengine, поэтому не ожидайте, что он скоро изменится. Если вы беспокоитесь о том, что не поймаете исключение, вы всегда можете добавить «исключение», которое улавливает все другие исключения, поэтому, если возникает ошибка, которая не является «TypeError» или «ProtocolBufferDecodeError», она все еще поймана –