FastAPI - 使用响应类下载字节内容时如何指定文件名?

问题描述 投票:0回答:1

我需要使用 FastAPI 下载存储在 MongoDB(而不是文件系统)中的文件。 我为此使用 FastAPI

Response
,因为
FileResponse
仅当文件位于文件系统中时才能使用。下载有效,但我找不到下载时指定
filename
的方法。

下载有效,但文件名默认为

response_SOME-NUMBER.txt
(来自 Swagger)。

这是代码。

@app.get("/files/{file_name}", responses = {200: {"content": {"text/html": {}}}}, response_class = Response)
def download_file(file_name: str):
    with MongoClient() as client:
        files_collection = client[DB][FILES_COLLECTION]
        result = files_collection.find_one({"file_name": file_name})
        content = result["file_data"]

    if result is not None:
        return Response(content=content, media_type="text/html")
    else:
        raise HTTPException(status_code=404, detail="File not found")

我想我可以在标题中添加名称以供 UI 检索,如下所示:

headers = {'Content-Disposition': f'attachment; filename="{download_file_name}"'}
return Response(content=content, headers=headers, media_type="text/html")

但是我想知道是否有一种方法可以像

FileResponse
那样指定名称。

file download fastapi response starlette
1个回答
0
投票

正如之前在以下答案中所描述的:

  1. 如何使用 Jinja2 Templates 和 FastAPI 上传 csv 文件,并修改后返回?

  2. 如何使用FastAPI从内存缓冲区返回PDF文件?

  3. 如何使用FastAPI返回并下载Excel文件?

  4. 使用 pdfkit 和 FastAPI 下载 PDF 文件

  5. 如何使用 JavaScript 从 FastAPI 后端下载文件 在前端获取API?

  6. 如何使用内存缓冲区生成并返回 PDF 文件 FastAPI?

  7. 如何使用FastAPI POST数据后下载文件?

  8. 如何出现选择下载位置的对话框 在前端,在下载文件之前,使用 FastAPI?

  9. 如何使用 FastAPI/Nextjs 显示 Matplotlib 图表而不在本地保存图表?

  10. 在 FastAPI 中渲染 NumPy 数组

当返回

Response
实例时,可以设置
Content-Disposition
响应标头,指示文件是否应该在浏览器/网页中 displayed (使用
inline
作为标头中第一个参数的值,这是默认值)或 downloaded(使用
attachment
),以及在文件下载到客户端设备时指定
filename
(可选)。

注意

filename
后面的字符串应始终放入引号中;但是,出于兼容性原因,许多浏览器尝试解析包含空格的未加引号的名称”(如果
filename
包含unicode字符,则应使用
filename*
参数并对文件名值进行编码 - 请参阅这个答案)。

示例

from FastAPI import Response
...

# use this, if you would like to have the file displayed inside the browser instead
# headers = {'Content-Disposition': 'inline; filename="out.pdf"'}

headers = {'Content-Disposition': 'attachment; filename="out.pdf"'}
return Response(content=content, headers=headers, media_type='application/pdf')

当返回

FileResponse
(继承自
Response
,与 FastAPI/Starlette 中的所有其他响应类一样)并设置
filename
参数时,FastAPI/Starlette 实际上在幕后设置
Content-Disposition 
为您提供标题。这个可以看
FileResponse
这里的实现类:

class FileResponse(Response):
    chunk_size = 64 * 1024

    def __init__(
        self,
        ...
        headers: typing.Mapping[str, str] | None = None,
        filename: str | None = None,
        content_disposition_type: str = "attachment",
    ) -> None:
        ...
        self.filename = filename
        ...
        self.init_headers(headers)
        if self.filename is not None:
            content_disposition_filename = quote(self.filename)
            if content_disposition_filename != self.filename:
                content_disposition = "{}; filename*=utf-8''{}".format(
                    content_disposition_type, content_disposition_filename
                )
            else:
                content_disposition = '{}; filename="{}"'.format(
                    content_disposition_type, self.filename
                )
            self.headers.setdefault("content-disposition", content_disposition)

如前所述,如上面

FileResponse
的实现所示,Starlette 会检查您传递的
filename
值是否包含非 ascii/unicode 字符,如果是,它将使用
filename*
参数来代替发送编码值。

因此,在您的情况下,您可以自己设置

Content-Disposition
标头(这可能是最合适的解决方案),如前面的示例所示,或者实现您自己的自定义响应类,继承自 Starlette 的
Response
,它将接受字节
content
和用于设置标头的
filename
参数,如上面的
FileResponse
所示。

© www.soinside.com 2019 - 2024. All rights reserved.