解析使用 Flask-Caching 存储的字节

Parse bytes stored using Flask-Caching

我使用 Flask-Caching 在 Redis 中缓存 Flask 视图的响应。直接从 Redis returns 一些字节获取缓存数据。我如何在 Python 中解析它以检查缓存值?

b'!\x80\x03cflask.wrappers\nResponse\nq\x00)\x81q\x01}q\x02(X\x07\x00\x00\x00headersq\x03cwerkzeug.datastructures\nHeaders\nq\x04)\x81q\x05}q\x06X\x05\x00\x00\x00_listq\x07]q\x08X\x0c\x00\x00\x00Content-Typeq\tX\x10\x00\x00\x00application/jsonq\n\x86q\x0basbX\x0c\x00\x00\x00_status_codeq\x0cK\xc8X\x07\x00\x00\x00_statusq\rX\x06\x00\x00\x00200 OKq\x0eX\x12\x00\x00\x00direct_passthroughq\x0f\x89X\t\x00\x00\x00_on_closeq\x10]q\x11X\x08\x00\x00\x00responseq\x12Xn\x00\x00\x00[\n  {\n    "desc": "pronoun object", \n    "tag": "CLO"\n  }, \n  {\n    "desc": "pronoun", \n    "tag": "CLS"\n  }\n]q\x13X\x01\x00\x00\x00\nq\x14\x86q\x15ub.'

Flask-Cache 使用 RedisCache backend provided by Werkzeug, which serializes values using pickle.dumps。它还会在反序列化时预先添加一个 ! 以获得帮助。你通常不应该直接弄乱这些值,让 Flask-Caching 处理它。

你可以使用pickletools.dis to safely examine the representation, then pickle.loads反序列化它。 安全说明pickle.loads 可以执行任意代码,因此请确保您首先使用 pickletools.dis.

了解不受信任的数据
>>> data = b'!\x80\x03cflask.wrappers\nResponse\nq\x00)\x81q\x01}q\x02(X\x07\x00\x00\x00headersq\x03cwerkzeug.datastructures\nHeaders\nq\x04)\x81q\x05}q\x06X\x05\x00\x00\x00_listq\x07]q\x08X\x0c\x00\x00\x00Content-Typeq\tX\x10\x00\x00\x00application/jsonq\n\x86q\x0basbX\x0c\x00\x00\x00_status_codeq\x0cK\xc8X\x07\x00\x00\x00_statusq\rX\x06\x00\x00\x00200 OKq\x0eX\x12\x00\x00\x00direct_passthroughq\x0f\x89X\t\x00\x00\x00_on_closeq\x10]q\x11X\x08\x00\x00\x00responseq\x12Xn\x00\x00\x00[\n  {\n    "desc": "pronoun object", \n    "tag": "CLO"\n  }, \n  {\n    "desc": "pronoun", \n    "tag": "CLS"\n  }\n]q\x13X\x01\x00\x00\x00\nq\x14\x86q\x15ub.'
>>> value = value[1:]  # strip leading !
>>> import pickletools
>>> pickletools.dis(data)
        0: \x80 PROTO      3
    2: c    GLOBAL     'flask.wrappers Response'
   27: q    BINPUT     0
   29: )    EMPTY_TUPLE
   30: \x81 NEWOBJ
   31: q    BINPUT     1
   33: }    EMPTY_DICT
   34: q    BINPUT     2
   36: (    MARK
   37: X        BINUNICODE 'headers'
   49: q        BINPUT     3
   51: c        GLOBAL     'werkzeug.datastructures Headers'
   84: q        BINPUT     4
   86: )        EMPTY_TUPLE
   87: \x81     NEWOBJ
   88: q        BINPUT     5
   90: }        EMPTY_DICT
   91: q        BINPUT     6
   93: X        BINUNICODE '_list'
  103: q        BINPUT     7
  105: ]        EMPTY_LIST
  106: q        BINPUT     8
  108: X        BINUNICODE 'Content-Type'
  125: q        BINPUT     9
  127: X        BINUNICODE 'application/json'
  148: q        BINPUT     10
  150: \x86     TUPLE2
  151: q        BINPUT     11
  153: a        APPEND
  154: s        SETITEM
  155: b        BUILD
  156: X        BINUNICODE '_status_code'
  173: q        BINPUT     12
  175: K        BININT1    200
  177: X        BINUNICODE '_status'
  189: q        BINPUT     13
  191: X        BINUNICODE '200 OK'
  202: q        BINPUT     14
  204: X        BINUNICODE 'direct_passthrough'
  227: q        BINPUT     15
  229: \x89     NEWFALSE
  230: X        BINUNICODE '_on_close'
  244: q        BINPUT     16
  246: ]        EMPTY_LIST
  247: q        BINPUT     17
  249: X        BINUNICODE 'response'
  262: q        BINPUT     18
  264: X        BINUNICODE '[\n  {\n    "desc": "pronoun object", \n    "tag": "CLO"\n  }, \n  {\n    "desc": "pronoun", \n    "tag": "CLS"\n  }\n]'
  379: q        BINPUT     19
  381: X        BINUNICODE '\n'
  387: q        BINPUT     20
  389: \x86     TUPLE2
  390: q        BINPUT     21
  392: u        SETITEMS   (MARK at 36)
  393: b    BUILD
  394: .    STOP
highest protocol among opcodes = 2
>>> import pickle
>>> response = pickle.loads(data)
>>> response.content_type
'application/json'
>>> response.json
[{'desc': 'pronoun object', 'tag': 'CLO'}, {'desc': 'pronoun', 'tag': 'CLS'}]