我使用Bottle接收压缩的请求正文。当请求的大小小时,一切都很好。但是,如果请求正文的大小稍大(例如,> = 20kb),则会引发IOError。
以下是用于读取和解压缩请求正文的代码:
@post("/receive")
def receive():
try:
f = request.body
g_f = gzip.GzipFile(fileobj=f)
content = g_f.read()
# other stuff on the content...
except IOError, e:
# handle the error
错误消息是:
[2015-09-07 16:27:27,967][ERROR ] Failed to decompress gzipped data: [Errno 9] read() on write-only GzipFile object
127.0.0.1 - - [07/Sep/2015 16:27:27] "POST /receive HTTP/1.1" 400 756
最佳答案
此问题是由用于创建GzipFile
对象的fileobj的读/写模式的继承引起的。
如果request.body
的大小小于20k,则Bottle
将整个二进制数据加载为StringIO
对象。 GzipFile
与StringIO
的关系很好,一切正常。
另一方面,如果request.body
的大小大于20k,则Bottle
将使用tempfile
模块为此请求正文创建一个临时文件,以确保平台一致性,这是由是“ w + b”。
但是,GzipFile会确定文件是否可读,不仅是tempfile
所获得的模式字符串,如果此字符串类似于'rxx',hasattr(fileobj, 'mode')
会将其视为可读,反之亦然。如果调用了不可读的GzipFile
的read()
函数,则会抛出GzipFile
。
由于IOError
将使用的文件模式为“ w + b”,因此GzipFile
仍将其视为“不可读”,所以,热闹!引发错误。要解决此问题,只需在创建GzipFile
对象时添加mode
参数:
try:
f = request.body
g_f = gzip.GzipFile(fileobj=f, mode='rb')
content = g_f.read()
# other stuff on the content...
except IOError, e:
# handle the error