Flask - 如何获取请求中每个文件的大小?
我在一个网站上处理文件上传,后端使用的是Flask。所有文件都是通过一个POST请求从客户端发送到服务器的,我用request
的getlist()
方法来逐个处理这些文件,然后用for循环来遍历它们。
if request.method == 'POST':
files = request.files.getlist('f[]')
问题是我想限制每个上传文件的大小为50MB,但我觉得MAX_CONTENT_LENGTH
是限制整个请求的大小。有没有办法让我检查request
对象中每个文件的大小,如果某个文件太大就拒绝它?用户可以上传一定数量的文件,但每个文件都必须小于50MB。
2 个回答
7
这里有两条信息可以帮助你:
有时候,Content-Length这个头部会被设置;解析这个头部可以确保它和实际上传的数据是准确的。如果是这样,你可以通过
FileStorage.content_length
属性来获取这个值。上传的文件是文件对象(可能是临时文件或者内存中的文件对象);你可以直接使用
file.seek()
和file.tell()
来确定它们的大小,而不需要读取整个文件。可能会有一种情况是内存中的文件对象不支持寻址,这时候你可以把整个文件读取到内存中,因为它的大小应该不会太大,不需要在磁盘上创建临时文件。
综合起来,测试单个文件大小的最佳方法是:
def get_size(fobj):
if fobj.content_length:
return fobj.content_length
try:
pos = fobj.tell()
fobj.seek(0, 2) #seek to end
size = fobj.tell()
fobj.seek(pos) # back to original position
return size
except (AttributeError, IOError):
pass
# in-memory file object that doesn't support seeking or tell
return 0 #assume small enough
然后在你的循环中:
for fobj in request.files.getlist('f[]'):
if get_size(fobj) > 50 * (1024 ** 2):
abort(413) # request entity too large
这样就可以完全避免把数据读入内存。
-4
把最大内容长度(MAX_CONTENT_LENGTH)设置为一个合理的值,这个值应该是所有文件总大小的上限。然后在处理每个文件之前,先检查一下文件的大小。
if request.method == 'POST':
files = request.files.getlist('f[]')
for f in files:
if len(f.read()) < (50 * 1024 * 1024):
# do something