从FastAPI服务器下载后.zip文件损坏问题求助
问题
通过FastAPI服务器下载使用Python shutil库创建的.zip文件时,前端console打印乱码,下载的文件损坏;含特殊字符的.txt文件也出现相同问题。
现有代码
1. 创建.zip文件的代码
shutil.make_archive(base_name = base_name , format = 'zip', root_dir = 'fileName.zip')
2. FastAPI路由方法
@app.get("/_archiveFiles_download", response_class = FileResponse) async def archiveFiles_download(request: Request): archiveFilePath = 'fileName.zip' return FileResponse(path = archiveFilePath)
3. JavaScript下载函数
// function to download archive file function downloadZipFiles() { $.get("./archiveFiles_download").done(function (data) { console.log(data) // prints garbage in console window // Create an anchor element for the download link const link = document.createElement("a"); const blob = new Blob([data1], { type: "application/x-zip-compressed" }); const url = URL.createObjectURL(blob); link.href = url; link.download = 'fileName_Download.zip'; // Set the desired file name link.click(); // Clean up the temporary URL URL.revokeObjectURL(url); }); }
问题原因
- 前端使用
$.get默认以文本格式解析二进制数据,导致zip/txt的二进制内容被错误转码,引发文件损坏、乱码 - shutil压缩代码参数错误:
root_dir应传入要压缩的源目录路径,而非目标zip文件名 - FastAPI响应未明确设置编码和正确的
Content-Disposition头,导致特殊字符处理异常
修复方案
1. 修正shutil压缩逻辑
root_dir指定要压缩的源目录,base_name为生成的zip文件名前缀(无需带.zip后缀,函数会自动添加):
import shutil # 示例:压缩"target_dir"目录,生成"fileName.zip" base_name = "fileName" shutil.make_archive( base_name=base_name, format='zip', root_dir='target_dir' # 改为要压缩的源目录路径 )
2. 优化FastAPI路由
添加文件存在检查,设置正确的媒体类型、编码和下载文件名:
from fastapi import FastAPI, Request, HTTPException from fastapi.responses import FileResponse import os import urllib.parse app = FastAPI() @app.get("/_archiveFiles_download", response_class=FileResponse) async def archiveFiles_download(request: Request): archiveFilePath = 'fileName.zip' if not os.path.exists(archiveFilePath): raise HTTPException(status_code=404, detail="文件不存在") # zip文件用application/zip;txt文件改为text/plain; charset=utf-8 return FileResponse( path=archiveFilePath, filename="fileName_Download.zip", media_type="application/zip", headers={ # 支持UTF-8文件名,解决特殊字符显示问题 "Content-Disposition": f"attachment; filename*=UTF-8''{urllib.parse.quote('fileName_Download.zip')}" } )
3. 修复前端下载逻辑
改用支持二进制数据的请求方式,指定responseType: 'blob':
方案一:使用Fetch API
function downloadZipFiles() { fetch("./_archiveFiles_download") .then(response => { if (!response.ok) throw new Error("下载请求失败"); return response.blob(); }) .then(blob => { const link = document.createElement("a"); const url = URL.createObjectURL(blob); link.href = url; link.download = 'fileName_Download.zip'; link.click(); URL.revokeObjectURL(url); }) .catch(err => console.error("下载出错:", err)); }
方案二:使用jQuery Ajax
function downloadZipFiles() { $.ajax({ url: "./_archiveFiles_download", method: "GET", xhrFields: { responseType: 'blob' // 明确获取二进制Blob数据 }, success: function(blob) { const link = document.createElement("a"); const url = URL.createObjectURL(blob); link.href = url; link.download = 'fileName_Download.zip'; link.click(); URL.revokeObjectURL(url); }, error: function(err) { console.error("下载失败:", err); } }); }
内容的提问来源于stack exchange,提问作者Sanyam
相关产品推荐
相关产品推荐

