在Google App Engine中,如何检查urlsafe创建的Key的输入有效性?

时间:2015-05-19 22:28:25

标签: google-app-engine google-cloud-datastore app-engine-ndb

假设我从用户输入websafe url

创建一个密钥
key = ndb.Key(urlsafe=some_user_input)

如何检查some_user_input是否有效?

我当前的实验表明,如果ProtocolBufferDecodeError (Unable to merge from string.)无效,则上述语句会抛出some_user_input异常,但无法从API中找到任何相关信息。有人可以确认这一点,并指出一些更好的方法来进行用户输入有效性检查而不是捕获异常吗?

非常感谢!

1 个答案:

答案 0 :(得分:10)

如果您尝试使用无效的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/project/main.py", line 10, in <module>
    from src.tim import handlers as handlers_
  File "/home/tim/git/project/src/tim/handlers.py", line 42, in <module>
    class ResetHandler(BaseHandler):
  File "/home/tim/git/project/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)

这是将“将输入合并到密钥”的实际尝试。

你可以在源代码中看到,在从urlsafe参数构造Key的过程中,不是很多都可能出错。首先,它检查输入是否为字符串,如果不是,则引发TypeError,如果是,但它不是“有效”,实际上引发了ProtocolBufferDecodeError

  

我当前的实验表明,如果some_user_input无效,但无法从API中找到任何相关内容,则上面的语句将抛出ProtocolBufferDecodeError(无法从字符串中合并。)异常。有人可以确认这个

确认的排序 - 我们现在知道也可以引发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'