重用验证文件大小的函数 [fastapi]

Reuse function that validates file size [fastapi]

我是 FastAPI 的新手。 我想验证上传文件的文件类型和文件大小,如果超过大小且与类型不匹配,则引发 Exception。此文件将上传至 S3 这就是我的代码的样子

@router.post("/upload/", status_code=200, description="***** Upload customer document asset to S3 *****")
async def upload(
        document_type: DocumentEnum,
        customer_id: UUID,
        current_user=Depends(get_current_user),
        fileobject: UploadFile = File(...)
):
    # delete the file from memory and rollover to disk to save unnecessary memory space
    fileobject.file.rollover()
    fileobject.file.flush()

    valid_types = [
        'image/png',
        'image/jpeg',
        'image/bmp',
        'application/pdf'
    ]
    await validate_file(fileobject, 5000000, valid_types)

    # .... Proceed to upload file 

我的 validate_file 函数如下所示

async def validate_file(file: UploadFile, max_size: int = None, mime_types: list = None):
    """
    Validate a file by checking the size and mime types a.k.a file types
    """
    if mime_types and file.content_type not in mime_types:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="You can only upload pdf and image for document"
        )
    if max_size:
        size = await file.read()
        if len(size) > max_size:
            raise HTTPException(
                status_code=status.HTTP_413_REQUEST_ENTITY_TOO_LARGE,
                detail="File size is too big. Limit is 5mb"
            )

    return file

现在,当文件上传到 S3 时,它的大小总是 0 bytes。 但是,如果我从 validate_file 函数中排除文件大小检查,那么原始文件将被上传并且没有问题。 如果validate_file函数是这样的,那么就可以正常上传了

async def validate_file(file: UploadFile, max_size: int = None, mime_types: list = None):
    """
    Validate a file by checking the size and mime types a.k.a file types
    """
    if mime_types and file.content_type not in mime_types:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="You can only upload pdf and image for document"
        )
            )

    return file

我不知道为什么会这样。预先感谢您的帮助。

当您在文件上调用 read 时,当前文件指针将位于您读取的内容的末尾。当您(或库)第二次调用 read 时,内部文件指针已经位于文件末尾。

可以使用await file.seek(0)将文件指针放在文件开头,这样下次读取时会再次读取相同的内容:

if max_size:
    size = await file.read()

    if len(size) > max_size:
        raise HTTPException(
            status_code=status.HTTP_413_REQUEST_ENTITY_TOO_LARGE,
            detail="File size is too big. Limit is 5mb"
        )

    await file.seek(0)

return file

您可能还想明确解析文件的 MIME 类型,而不是相信用户所说的文件是什么 - 您可以 use mimetypes.guess_type or something similar 做到这一点。