【问题标题】:Receiving gzip with Flask使用 Flask 接收 gzip
【发布时间】:2015-02-03 16:58:35
【问题描述】:

我正在尝试从 HTTP POST 到 Flask (v0.10) 接收 gzip 压缩的 JSON 文件。我觉得在尝试打开 gzip 之前可能会发布一些额外的数据需要删除。

这是我的代码:

from flask import Flask, jsonify, request, abort
import gzip, StringIO
app = Flask(__name__)

# Handle posted data
@app.route('/', methods = ['POST'])
def post_gzip():

    # Check for a supported media type
    if (request.headers['Content-Type'] == 'application/x-gzip'):

        file = request.data
        f = gzip.open(file, 'rb')        

        return f;

    else:
        # 415 Unsupported Media Type
        abort(415)

if __name__ == "__main__":
    app.debug = True
    app.run()

我正在使用 cURL 将压缩的 JSON 文件发布到 Flask,如下所示:

curl -X POST -d @test.json.gz http://127.0.0.1:5000/ -H "Content-Type:application/x-gzip" -H "Content-Encoding:gzip"

我收到的错误是:

UnicodeDecodeError: 'utf8' codec can't decode byte 0x8b in position 1: invalid start byte

Flask 似乎无法将接收到的数据视为 gz 文件。也许 request.data 甚至不是正确的使用方法。

有好心人能给我指出这个正确的方向吗?

【问题讨论】:

    标签: python curl flask gzip


    【解决方案1】:

    对于 Python 3,我将只使用 gzip.decompress(request.data),它返回一个解压缩的字符串。

    只是一个方便的速记功能,8年前添加的:)

    如果你想看代码,可以找到here

    2019 年编辑:写了一个简单的flask extension,您可以在您的应用中使用。

    【讨论】:

    • 很好,感谢烧瓶扩展!只是想知道:您是否经历过任何性能影响?我们有一个端点,它接受一个普通的 JSON 对象,该对象包含一个带有 gzip 编码字符串的属性。如果这个字符串在端点内被 gzip 解码,性能是惊人的。当你的扩展作为装饰器时,吞吐量会大大降低(以防它必须启动)。有什么想法吗?
    • 有兴趣的可以继续和@boesinghere讨论
    【解决方案2】:

    接受的答案对于 Python 2 是正确的,但如果您在 Python 3 上尝试此操作,则需要使用 BytesIO 而不是 StringIO:

    compressed_data = io.BytesIO(request.data)
    text_data = gzip.GzipFile(fileobj=compressed_data, mode='r')
    

    【讨论】:

      【解决方案3】:

      您导入了StringIO,但从未真正使用它,并将字符串提供给需要文件名的gzip.open。您收到的错误来自 gzip 在尝试打开文件之前尝试将文件名解码为 Unicode。 下面利用StringIO制作一个gzip可以使用的类文件对象:

      ...
      fakefile = StringIO.StringIO(request.data) # fakefile is now a file-like object thta can be passed to gzip.GzipFile:
      uncompressed = gzip.GzipFile(fileobj=fakefile, mode='r')
      return uncompressed.read()
      ...
      

      编辑: 我已经重构了下面的代码并放置了相关的 cmets 以便更好地理解发生了什么:

      from flask import Flask, request
      import gzip, StringIO
      
      app = Flask(__name__)
      
      @app.route('/', methods = ['POST'])
      def my_function():
      
          # `request.data` is a compressed string and `gzip.GzipFile`
          # doesn't work on strings. We use StringIO to make it look
          # like a file with this:
          fakefile = StringIO.StringIO(request.data)
      
          # Now we can load the compressed 'file' into the 
          # `uncompressed` variable. While we're at it, we
          # tell gzip.GzipFile to use the 'rb' mode
          uncompressed = gzip.GzipFile(fileobj=fakefile, mode='rb')
      
          # Since StringIOs aren't real files, you don't have to 
          # close the file. This means that it's safe to return
          # its contents directly:
          return uncompressed.read()
      
      if __name__ == "__main__":
          app.debug = True
          app.run()
      

      【讨论】:

      • 现在我收到此错误:IOError: [Errno 22] invalid mode ('rb') or filename: '\x1f\x8b\x08\x08\xae\x8e\x dcT\x02\xffflask_test.json\x1f\xc0\xb5\xb6\xfb\x072\xe8\x1d\xb4>\x08\x17@\xcd\xd 9\x88L\xceN\xe0\x82\x86d\x9e\x8dh \xb1\x84\xfd\x04)\xe1\xd1\x81\x91\x9b\x07\xe1&0 Q?\x1a\x111V\xcd\xe5\xa7\xf5\xef\xa7E\x9b\x06\x11z\xeb\ xc6\xa4\xff\xd1F\xd97\xbf\x94\xe2y!\xe8q\xb6d\x94\x15\xb7\x94\xddf\xe5\x9c\xbfp\xc6\xe8/>`\x8c?'
      • from flask import Flask, request import gzip, StringIO app = Flask(__name__) @app.route('/', methods = ['POST']) def my_function(): fakefile = StringIO.StringIO(request.data) uncompressed = gzip.GzipFile(fakefile.read()) file_content = f.read() f.close() return file_content if __name__ == "__main__": app.debug = True app.run()
      • 如果我将 uncompressed = gzip.GzipFile(fakefile.read()) 更改为 uncompressed = gzip.GzipFile(fakefile) 我得到 TypeError: coercing to Unicode: need string or buffer, instance found
      • 请阅读以下内容:docs.python.org/2/library/gzip.html#gzip.GzipFilegzip.GzipFile 采用 fileobj 命名参数的类文件参数。您通过省略参数将其作为文件名传递。我的答案中的第 3 行显示了正确的用法。 gzip.GzipFile(fakefile) 在您的用例中不正确。
      • 感谢 Iskren 的支持,我的错误是省略了 fileobj。我现在遇到 CRC 检查问题。我会坚持下去的。再次感谢。 IOError: CRC check failed 0x2fe8c670 != 0x0L
      猜你喜欢
      • 2017-03-16
      • 1970-01-01
      • 2020-01-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多