用Flask接收gzip

nov*_*ket 7 python curl gzip flask

我正在尝试从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()
Run Code Online (Sandbox Code Playgroud)

我正在使用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"
Run Code Online (Sandbox Code Playgroud)

而我收到的错误是:

UnicodeDecodeError: 'utf8' codec can't decode byte 0x8b in position 1: invalid start byte
Run Code Online (Sandbox Code Playgroud)

似乎Flask无法将收到的数据视为gz文件.也许request.data不是正确使用的东西.

某个善良的人能指出我正确的方向吗?

小智 10

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

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

如果您想查看代码,可以在此处找到它.


Isk*_*ren 6

您导入但从未实际使用它并提供需要文件名的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()
...
Run Code Online (Sandbox Code Playgroud)

编辑:我重构了下面的代码并添加了相关注释,以便更好地理解正在发生的事情:

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()
Run Code Online (Sandbox Code Playgroud)


小智 6

可接受的答案对于Python 2是正确的,但以防万一,如果您正在使用Python 3进行尝试,则需要使用BytesIO而不是StringIO:

compressed_data = io.BytesIO(request.data)
text_data = gzip.GzipFile(fileobj=compressed_data, mode='r')
Run Code Online (Sandbox Code Playgroud)