2014-02-28 70 views
1

我在網站上進行了上傳,並使用燒瓶作爲後端。該文件是在一個POST請求發送所有從客戶機到服務器,和我單獨處理它們通過使用requestgetlist()方法,並用遍歷,for循環:Flask - 獲取請求中每個文件的大小?

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

問題是,我想將每個文件上傳的大小限制爲50mb,但我假設MAX_CONTENT_LENGTH限制了整個請求的大小。有沒有一種方法可以評估request對象中每個單獨文件的大小,並在文件太大時拒絕該文件?用戶可以上傳一定數量的文件,但每個文件都需要低於50MB。

回答

-1

將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 
+2

我只是給你發送一個10GB的文件,然後導致你的服務器崩潰,出現內存錯誤。 –

+0

好點,更新。謝謝。 – chishaku

3

有兩條信息,您可以使用此:

  1. 有時候Content-Length頭設置;解析確保這對於上傳的實際數據來說是準確的。如果是這樣,你可以從FileStorage.content_length attribute得到這個值。

  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 

這避免了數據完全讀取到內存中。

+0

應該接受答案,因爲它不會將字節加載到內存中。 –

+0

413不是更好的代碼嗎? –

+0

@ChristopheRoussy:是的,一個413可能是一個更好的響應代碼,更新。 –