如何使用 Flask send_file 下载内存中的 ZIP-FILE 对象

alp*_*ric 1 python flask

Flask HTTP 服务器运行时server.py

import os, io, zipfile, time

from flask import Flask, request, send_file

app = Flask(__name__)

FILEPATH = '/change/it/to/any_file.path'

@app.route('/download', methods=['GET','POST'])
def download():     
    fileobj = io.BytesIO()
    with zipfile.ZipFile(fileobj, 'w') as zip_file:
        zip_info = zipfile.ZipInfo(FILEPATH)
        zip_info.date_time = time.localtime(time.time())[:6]
        zip_info.compress_type = zipfile.ZIP_DEFLATED
        with open(FILEPATH, 'rb') as fd:
            zip_file.writestr(zip_info, fd.read())
    fileobj.seek(0)

    return send_file(fileobj.read(), mimetype='zip', as_attachment=True, attachment_filename = '%s.zip' % os.path.basename(FILEPATH)) 

app.run('0.0.0.0', 80)
Run Code Online (Sandbox Code Playgroud)

发送client.py下载文件的请求:

import requests 
response = requests.post('http://127.0.0.1:80/download', timeout = 6000)
print type(response)
Run Code Online (Sandbox Code Playgroud)

提出serverTypeError

TypeError: file() argument 1 must be encoded string without NULL bytes, not str

如何解决这个问题?

alp*_*ric 5

可能的解决方案之一将使用Flask.make_response方法:

from flask import Flask, request, send_file, make_response

@app.route('/download', methods=['GET','POST'])
def download():     
    fileobj = io.BytesIO()
    with zipfile.ZipFile(fileobj, 'w') as zip_file:
        zip_info = zipfile.ZipInfo(FILEPATH)
        zip_info.date_time = time.localtime(time.time())[:6]
        zip_info.compress_type = zipfile.ZIP_DEFLATED
        with open(FILEPATH, 'rb') as fd:
            zip_file.writestr(zip_info, fd.read())
    fileobj.seek(0)

    response = make_response(fileobj.read())
    response.headers.set('Content-Type', 'zip')
    response.headers.set('Content-Disposition', 'attachment', filename='%s.zip' % os.path.basename(FILEPATH))
    return response
Run Code Online (Sandbox Code Playgroud)