Flask - 如何获取请求中每个文件的大小?

3

我正在一个网站上上传文件,并使用flask作为后端。所有文件都通过客户端发送到服务器的一个POST请求中,我使用requestgetlist()方法逐个处理它们,并通过for循环进行迭代:

if request.method == 'POST':
    files = request.files.getlist('f[]')

问题是我希望限制每个上传的文件大小为50MB,但我认为MAX_CONTENT_LENGTH限制了整个请求的大小。是否有一种方法可以评估request对象中每个单独文件的大小,并在文件过大时拒绝它?用户可以上传一组文件,但每个文件都必须小于50MB。

2个回答

7

这里有两个可用的信息:

  1. 有时会设置Content-Length头;解析确保上传数据的准确性。如果是这样,您可以从FileStorage.content_length属性获取此值。

  2. 上传的文件是文件对象(在磁盘上的临时文件或内存中的类似文件的对象);只需在这些文件对象上使用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

这样可以避免完全将数据读入内存。

应该被接受的答案,因为它不会将字节加载到内存中。 - Christophe Roussy
@ChristopheRoussy:是的,在这里使用413可能会是一个更好的响应代码,已更新。 - Martijn Pieters

-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

6
我会直接发送给你一个10GB的文件,这样会导致你的服务器出现内存错误而崩溃。 - Martijn Pieters

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接