首页 > 解决方案 > 如何在使用带有 request.post 方法的 files 参数上传文件时应用压缩

问题描述

将 Flask 服务器配置为支持压缩:

服务器.py

import os 
import json 
import tempfile
from flask import Flask, request
from flask_compress import Compress

app = Flask(__name__)
app.config['COMPRESS_MIMETYPES'] = set(['text/html', 'text/css', 'text/xml', 'application/json', 'application/javascript'])  
app.config['COMPRESS_LEVEL'] = 6
app.config['COMPRESS_MIN_SIZE'] = 500
Compress(app)


@app.route('/', methods=['GET', 'POST'])
def index():
    print('get_json: %s get_data: %s' % (type(request.get_json()), type(request.get_data())) )

    for key, value in request.files.items():
        if value.content_type == 'application/json':
            data = json.loads(value.stream.read())
            print('got json data %s' % data)

        elif value.content_type == 'application/octet-stream':
            dst_filepath = os.path.join(tempfile.mktemp(), value.filename)
            if not os.path.exists(os.path.dirname(dst_filepath)):
                os.makedirs(os.path.dirname(dst_filepath))

            with open(dst_filepath, 'wb') as fd:
                for chunk in value: 
                    fd.write(chunk)
                print('saved file as %s' % dst_filepath)

    return 'OK', 200

app.run('0.0.0.0', 80)

client.py发送request带有 json 字典和文件数据的单曲。

客户端.py

import requests 
import json
import os 

payload = {"param_1": "value_1", "param_2": "value_2"}

filepath = '/file/path/to/local_file.zip'

data = {'json': ('some-json', json.dumps(payload), 'application/json'),
        'file': (os.path.basename(filepath), open(filepath, 'rb'), 'application/octet-stream')}

response = requests.post('http://127.0.0.1:80/', files = data)

为了尽量减少上传时间,我想发送压缩文件数据(连同 json 数据)的请求。如何实现?

后来编辑:

看起来有一个方法headers参数request.post()可用于指定编码类型。

response = requests.post('http://127.0.0.1:80/', 
                          files = data,
                          headers = {'Accept-Encoding': 'gzip'})

但是我们如何压缩data用于存储文件数据的字典和 json 字典呢?

标签: pythonhttpflaskrequestpython-requests

解决方案


该解决方案使用gzip模块在客户端发送文件时压缩文件的二进制数据,并在服务器接收到发送的压缩文件数据时解压缩。

服务器.py

#!/usr/bin/env python
import os 
import io 
import json 
import gzip
import hashlib
import tempfile
from flask import Flask, request

app = Flask(__name__)

@app.route('/', methods=['GET', 'POST'])
def index():
    print('get_json: %s get_data: %s' % (type(request.get_json()), type(request.get_data())) )

    for key, file_storage in request.files.items():

        if file_storage.content_type == 'application/json':
            data = json.loads(file_storage.stream.read())
            print('got json data %s' % data)

        elif file_storage.content_type == 'application/octet-stream':

            zip_str = ''.join([chunk for chunk in file_storage])
            zip_str_md5_hash = hashlib.md5(zip_str).hexdigest()

            zip_filepath = os.path.join(tempfile.mktemp(), file_storage.filename)

            if not os.path.exists(os.path.dirname(zip_filepath)):
                os.makedirs(os.path.dirname(zip_filepath))

            with open(zip_filepath, 'wb') as fd:
                for chunk in zip_str: 
                    fd.write(chunk)

            filepath = zip_filepath.replace('.zip', '')

            zip_str_file = gzip.GzipFile(fileobj=io.BytesIO(zip_str)) 
            with open(filepath, 'wb') as fd:
                for chunk in zip_str_file.read():
                    fd.write(chunk)

            print('compressed str as zip_str: %s' % hashlib.md5(zip_str).hexdigest())
            print('read compressed data as zip_filepath: %s' % hashlib.md5(open(zip_filepath, 'rb').read()).hexdigest()) 
            print('read uncompressed filepath: %s' % hashlib.md5(open(filepath, 'rb').read()).hexdigest())
            print('uncompressed zip_str as zip_str_file: %s' % hashlib.md5(zip_str_file.read()).hexdigest())

    return 'OK', 200

app.run('0.0.0.0', 80)

客户端.py

import requests 
import json
import os 
import gzip
import io
import hashlib

payload = {"param_1": "value_1", "param_2": "value_2"}

filepath = '/file/path/to/local_file.zip'

bytes_io = io.BytesIO()
gzip_file = gzip.GzipFile(fileobj=bytes_io, mode='w')
open_file = open(filepath, 'rb')
gzip_file.write(bytes(open_file.read()))
gzip_file.close()

zip_str = bytes_io.getvalue()

data = {'json': ('some-json', json.dumps(payload), 'application/json'),
        'file': ('%s.zip'%os.path.basename(filepath), zip_str, 'application/octet-stream')}

response = requests.post('http://127.0.0.1:80', files = data)

print('file open read data as filepath %s' % hashlib.md5(open(filepath, 'rb').read()).hexdigest())
print('bytes_io%s' % hashlib.md5(bytes_io.getvalue()).hexdigest())
print('compressed str as zip_str %s' % hashlib.md5(zip_str).hexdigest())

推荐阅读