6

我正在用 Python 和 CGI​​ 编写一个小型网站,用户可以在其中上传 zip 文件和下载其他用户上传的文件。目前,我能够正确上传 zip,但在将文件正确发送给用户时遇到了一些麻烦。我的第一种方法是:

file = open('../../data/code/' + filename + '.zip','rb')

print("Content-type: application/octet-stream")
print("Content-Disposition: filename=%s.zip" %(filename))
print(file.read())

file.close()

但很快我意识到我必须将文件作为二进制文件发送,所以我尝试了:

print("Content-type: application/octet-stream")
print("Content-Disposition: filename=%s.zip" %(filename))
print('Content-transfer-encoding: base64\r')
print( base64.b64encode(file.read()).decode(encoding='UTF-8') )

以及它的不同变体。它只是行不通;Apache 引发“来自脚本的格式错误的标头”错误,所以我想我应该以其他方式对文件进行编码。

4

3 回答 3

6

您需要在标题后打印一个空行,并且您的 Content-disposition 标题缺少类型(attachment):

print("Content-type: application/octet-stream")
print("Content-Disposition: attachment; filename=%s.zip" %(filename))
print()

您可能还想使用更有效的方法来上传结果文件;用于shutil.copyfileobj()将数据复制到sys.stdout.buffer

from shutil import copyfileobj
import sys

print("Content-type: application/octet-stream")
print("Content-Disposition: attachment; filename=%s.zip" %(filename))
print()

with open('../../data/code/' + filename + '.zip','rb') as zipfile:
    copyfileobj(zipfile, sys.stdout.buffer)

在任何情况下,您都不应该使用print()二进制数据;你得到的只是b'...'字节文字语法。该sys.stdout.buffer对象是底层二进制 I/O 缓冲区,直接将二进制数据复制到该缓冲区。

于 2013-08-20T16:35:34.760 回答
5

标头格式错误,因为出于某种原因,Python 在发送文件后发送它。

您需要做的是在标头之后立即刷新标准输出:

sys.stdout.flush()

然后把文件拷贝

于 2014-06-16T03:25:32.993 回答
3

这对我有用,我正在运行 Apache2 并通过 cgi 加载此脚本。Python 3 是我的语言。

您可能必须用您的 python 3 bin 路径替换第一行。

#!/usr/bin/python3
import cgitb
import cgi
from zipfile import ZipFile
import sys

# Files to include in archive
source_file = ["/tmp/file1.txt", "/tmp/file2.txt"]

# Name and Path to our zip file.
zip_name = "zipfiles.zip"
zip_path = "/tmp/{}".format(zip_name)

with ZipFile( zip_path,'w' ) as zipFile:
    for f in source_file:
        zipFile.write(f);

# Closing File.
zipFile.close()

# Setting Proper Header.
print ( 'Content-Type:application/octet-stream; name="{}"'.format(zip_name) );
print ( 'Content-Disposition:attachment; filename="{}"\r\n'.format(zip_name) );

# Flushing Out stdout.
sys.stdout.flush()

bstdout = open(sys.stdout.fileno(), 'wb', closefd=False)
file = open(zip_path,'rb')
bstdout.write(file.read())
bstdout.flush()
于 2016-11-21T12:34:55.873 回答