我有一个 GET 端点,它应该返回一个巨大的文件(500Mb)。 我正在使用
FileResponse
来做到这一点(为了清晰起见,简化了代码):
async def get_file()
headers = {"Content-Disposition": f"attachment; filename={filename}"}
return FileResponse(file_path, headers=headers)
然后该文件立即保存。
例如,我有一个大小为 500 MB 的文件,当我在 UI 上单击“下载”时,我必须等待一分钟或其他时间,直到显示“保存对话框”。然后,当我单击“保存”时,文件会立即保存。显然前端正在等待文件下载,我需要的是前端立即显示“保存对话框”,然后在后台开始下载。
我需要的是这样的:立即显示对话框,然后用户单击“保存”后等待下载完成。
那么我怎样才能实现这一目标呢?
您尚未提供有关项目客户端的任何详细信息,但客户端似乎很可能使用异步 JavaScript 请求(例如
fetch()
请求)来请求资源(文件)。如果您使用 Swagger UI 自动文档,它还会在幕后使用 Fetch API — 请参阅 这个答案。
当使用
fetch()
或任何其他异步 JavaScript 库请求如此大的文件 (500 MB) 或任何资源时(如这个答案以及这个答案和这个答案中所示),必须完全接收来自服务器的响应,然后才能进一步显示窗口/对话框以选择您想要下载文件的位置(请参阅之前为 Swagger UI 案例提供的链接答案)。
因此,您可以使用以下方法之一来实现预先显示用于选择下载位置的窗口/对话框,而不是使用 JavaScript 来请求资源:
解决方案
filename
的
FileResponse
参数,例如:return FileResponse(file_path, filename="BigFile.zip")
将添加带有
Content-Disposition
标志的
attachment
响应标头,指示应下载文件而不是在浏览器中查看文件。但是,如果您想确定这一点,您可以自己添加标头,如here和here所示,如下所示:
@app.get("/download")
def download_file():
file_path = "files/BigFile.zip"
headers = {'Content-Disposition': 'attachment; filename="BigFile.zip"'}
return FileResponse(file_path, headers=headers)
前端
<a>
标签定义的超链接:
<a href="/download">Download</a>
如果后端未设置包含
Content-Disposition
标志的
attachment
响应标头,您可以在前端的超链接中使用 download
属性,该属性“指定目标(href 中指定的文件)属性)将在用户单击超链接时下载”(请参阅相关的 w3schools 文章):
<a href="/download" download>Download</a>
使用按钮代替超链接
<button>
<a href="/download" style="text-decoration: none; color: unset; cursor: default;" download>Download</a>
</button>
或
<button onclick="document.getElementById('my_link').click()">Download</button>
<a id="my_link" href="/download" download hidden></a>
或
<form method="get" action="/download">
<button type="submit">Download</button>
</form>
或
<button type="submit" onclick="window.location.href='/download'">Download</button>
对于上面最后两个选项,请记住在服务器端设置带有 Content-Disposition
标志的
attachment
响应标头,以便下载文件而不是在浏览器中查看文件,就像您可以的那样在这些情况下,没有 <a>
超链接 download
属性。通过 JavaScript 启动文件下载
<button>
元素是可选的;如果您不需要用户单击按钮,而是希望通过 JS 函数自动触发文件下载,您可以将其删除。
<a id="my_link" href="/download" download hidden></a>
<button onClick="downloadFile()">Download</button>
<script>
function downloadFile() {
document.getElementById("my_link").click()
}
</script>