如何限制Python Fastapi Post请求上传文件大小?

发布于 2025-01-31 08:35:13 字数 481 浏览 3 评论 0原文

我正在创建一个fastapi python应用程序,其中用户上传要处理的文件。我不希望该文件超过大小x(在字节中)。

在邮政请求将文件存储在内存中之前,如何限制文件上传大小?

我正在使用Uivcorn进行测试,但我希望可以使用Google Cloud Platform(GCP)部署此代码。我不确定是否可以在Python代码端或服务器配置侧进行此操作。

代码段:

from fastapi import (
     FastAPI, 
     Path, 
     File, 
     UploadFile, 
) 

app = FastAPI()

@app.post("/")
async def root(file: UploadFile  = File(...)):
     text = await file.read()
     text = text.decode("utf-8")
     return len(text)

I am creating a FastAPI Python application where a user uploads a file to be processed. I do not want the file to exceed size X (in bytes).

How do I limit the file upload size before the POST request stores the file in memory?

I am using uivcorn for testing but I am expecting to deploy this code with Google Cloud Platform (GCP). I am not sure if this can be done on the python code-side or server configuration-side.

Code Snippet:

from fastapi import (
     FastAPI, 
     Path, 
     File, 
     UploadFile, 
) 

app = FastAPI()

@app.post("/")
async def root(file: UploadFile  = File(...)):
     text = await file.read()
     text = text.decode("utf-8")
     return len(text)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

遮了一弯 2025-02-07 08:35:13

我找到了一个Python库,可以通过Fastapi中间件来照顾这一点。如果上传文件太大,它将抛出413 HTTP错误; “错误:请求实体太大”

from starlette_validation_uploadfile import ValidateUploadFileMiddleware

 from fastapi import (
      FastAPI, 
      Path, 
      File, 
      UploadFile, 
 ) 


app = FastAPI()

#add this after FastAPI app is declared 
app.add_middleware(
        ValidateUploadFileMiddleware,
        app_path="/",
        max_size=1048576, #1Mbyte
        file_type=["text/plain"]
)


 @app.post("/")
 async def root(file: UploadFile  = File(...)):
      #...do something with the file
      return {"status: upload successful"}

I found a python library that takes care of this via FastAPI middleware. If the upload file is too large it will throw a 413 HTTP error; "Error: Request Entity Too Large"

from starlette_validation_uploadfile import ValidateUploadFileMiddleware

 from fastapi import (
      FastAPI, 
      Path, 
      File, 
      UploadFile, 
 ) 


app = FastAPI()

#add this after FastAPI app is declared 
app.add_middleware(
        ValidateUploadFileMiddleware,
        app_path="/",
        max_size=1048576, #1Mbyte
        file_type=["text/plain"]
)


 @app.post("/")
 async def root(file: UploadFile  = File(...)):
      #...do something with the file
      return {"status: upload successful"}
魔法少女 2025-02-07 08:35:13

它通常通过Web服务器(例如Nginx或Apache)控制,但是如果要在服务器端控制,则可以使用此代码:

from fastapi import (
    FastAPI,
    Path,
    File,
    UploadFile,
)

app = FastAPI()

@app.post("/")
async def root(file: UploadFile = File(...)):
    if len(await file.read()) >= 8388608:
        return {"Your file is more than 8MB"}

it usually controls by web server like nginx or Apache but if you want to control in the server side you can use this code:

from fastapi import (
    FastAPI,
    Path,
    File,
    UploadFile,
)

app = FastAPI()

@app.post("/")
async def root(file: UploadFile = File(...)):
    if len(await file.read()) >= 8388608:
        return {"Your file is more than 8MB"}
挽清梦 2025-02-07 08:35:13

您可以使用中间件。我使用了此一个,它的用法很不错

(我更改了原始代码a位):

middleware.py:

from typing import Optional
from fastapi import HTTPException

class ContentSizeLimitMiddleware:
    """Content size limiting middleware for ASGI applications

    Args:
      app (ASGI application): ASGI application
      max_content_size (optional): the maximum content size allowed in bytes, None for no limit
    """

    def __init__(
        self,
        app,
        max_content_size: Optional[int] = None,
    ):
        self.app = app
        self.max_content_size = max_content_size

    def receive_wrapper(self, receive):
        received = 0

        async def inner():
            nonlocal received
            message = await receive()
            if message["type"] != "http.request" or self.max_content_size is None:
                return message
            body_len = len(message.get("body", b""))
            received += body_len

            if received > self.max_content_size:
                raise HTTPException(detail="File is too big", status_code=413)

            return message

        return inner

    async def __call__(self, scope, receive, send) -> None:
        if scope["type"] != "http":
            await self.app(scope, receive, send)
            return

        wrapper = self.receive_wrapper(receive)
        await self.app(scope, wrapper, send)

main.py:

app.add_middleware(ContentSizeLimitMiddleware, max_content_size=5 * 1024 * 1024) # 5MB

此解决方案仅读取文件的必要部分,并拒绝请求

以此starlette视图为例:

@app.route("/documents/upload", methods=["POST"])
def upload_document(request):
    data = await request.body()
    if len(data) > Config.MAX_FILE_SIZE:
        return api_400(
            f"This file exceeds the maximum file size we support at this time ({Config.MAX_FILE_SIZE})",
            code=MAX_FILE_SIZE_EXCEEDED,
        )
    ...

如果最大文件大小为5MB,并且上传的文件为50MB,则此实现在拒绝请求之前,将整个50MB读取到内存中。

You can use middleware. I used this one and it works nice

Usage (I change the original code a bit):

middleware.py:

from typing import Optional
from fastapi import HTTPException

class ContentSizeLimitMiddleware:
    """Content size limiting middleware for ASGI applications

    Args:
      app (ASGI application): ASGI application
      max_content_size (optional): the maximum content size allowed in bytes, None for no limit
    """

    def __init__(
        self,
        app,
        max_content_size: Optional[int] = None,
    ):
        self.app = app
        self.max_content_size = max_content_size

    def receive_wrapper(self, receive):
        received = 0

        async def inner():
            nonlocal received
            message = await receive()
            if message["type"] != "http.request" or self.max_content_size is None:
                return message
            body_len = len(message.get("body", b""))
            received += body_len

            if received > self.max_content_size:
                raise HTTPException(detail="File is too big", status_code=413)

            return message

        return inner

    async def __call__(self, scope, receive, send) -> None:
        if scope["type"] != "http":
            await self.app(scope, receive, send)
            return

        wrapper = self.receive_wrapper(receive)
        await self.app(scope, wrapper, send)

main.py:

app.add_middleware(ContentSizeLimitMiddleware, max_content_size=5 * 1024 * 1024) # 5MB

This solution reads only the necessary part of the file and reject the request

Take this Starlette view for example:

@app.route("/documents/upload", methods=["POST"])
def upload_document(request):
    data = await request.body()
    if len(data) > Config.MAX_FILE_SIZE:
        return api_400(
            f"This file exceeds the maximum file size we support at this time ({Config.MAX_FILE_SIZE})",
            code=MAX_FILE_SIZE_EXCEEDED,
        )
    ...

If the maximum file size is 5MB, and the uploaded file was 50MB, then this implementation reads the entire 50MB into memory before rejecting the request.

旧人 2025-02-07 08:35:13

我正在使用fastapi。我在端点中用用过uploadfile。

@app.route("/documents/upload")
def upload_document(file: UploadFile = File(...),
    custom_fields_mapping: str = Form(None)):
    try:
        if file.size > 500*1024: 
           return {"success": True, "message": "BOD processing started in the background."}
    

I am using FastAPI. I used UploadFile in the endpoint.

@app.route("/documents/upload")
def upload_document(file: UploadFile = File(...),
    custom_fields_mapping: str = Form(None)):
    try:
        if file.size > 500*1024: 
           return {"success": True, "message": "BOD processing started in the background."}
    
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文