google-app-engine - 在 Google App Engine 中,如何检查 urlsafe 创建的 key 的输入有效性?

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

假设我从用户输入的网络安全 url 创建一个 key

key = ndb.Key(urlsafe=some_user_input)

如何检查 some_user_input 是否有效?

我目前的实验表明,如果 some_user_input 无效,上面的语句将抛出 ProtocolBufferDecodeError (Unable to merge from string.) 异常,但无法从API。有人可以确认这一点,并指出一些更好的用户输入有效性检查方法,而不是捕获异常吗?

非常感谢!

最佳答案

如果您尝试使用无效的 urlsafe 参数构造 Key

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)

这是实际尝试“将输入合并到 key 中”的地方。


您可以在源代码中看到,在从 urlsafe 参数构造 Key 的过程中,不会出现很多错误。首先它检查输入是否是 string,如果不是,则引发 TypeError,如果是但不是“有效”,实际上是 ProtocolBufferDecodeError 被提出。


My current experiment shows that statement above will throw ProtocolBufferDecodeError (Unable to merge from string.) exception if the some_user_input is invalid, but could not find anything about this from the API. Could someone kindly confirm this

有点确认 - 我们现在知道也可以引发 TypeError。

and point me some better way for user input validity checking instead of catching the exception?

这是检查有效性的好方法!如果应用引擎已经完成检查,为什么还要自己检查?代码片段可能看起来像这样(不是工作代码,只是一个例子)

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'

关于google-app-engine - 在 Google App Engine 中,如何检查 urlsafe 创建的 key 的输入有效性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30337240/

相关文章:

linux - 我们如何才能灵活地为 Google App Engine 更改操作系统?或者我们可以这样做吗?

node.js - Google App Engine Nodejs 错误 409

python - 正确使用 GAE ndb.CompulatedProperty

google-app-engine - AppEngine 平台警告 : urllib3 is using URLFetch on Google App Engine sandbox instead of sockets

java - 使用 objectify 实体模型进行模拟测试时的 Ref & Key 问题

python - Google Cloud Datastore 中事务的高度一致性

java - Google App Engine 数据存储区支持哪些数据类型?

google-app-engine - 是否可以更改实体的命名空间 (NDB)

python - 将结构化属性添加到 NDB 中的模型

java - 在 Google AppEngine 数据存储中使用 500 多个字符字符串