FastAPI+Vuetify多图片下载后无法加载问题求助
问题描述
尝试通过Vuetify前端从FastAPI服务器下载多张图片并展示在卡片组件上,但图片无法加载,显示“Image load failed”错误。文件名属性已成功加载,不清楚图片无法正常加载的原因。
后端FastAPI代码
常量定义
DOWNOAD_PATH = "imgSearch"
下载函数
def download(file_path): if os.path.isfile(file_path): return FileResponse(path=file_path, media_type="image/jpg", filename=os.path.basename(file_path)) return None
接口路由
@router.get('/img/download') async def download_images(): lsImages = [] i = 0 for imgFilename in os.listdir(DOWNOAD_PATH): lsImages.append(download(os.path.join(DOWNOAD_PATH, imgFilename))) print("Image: " + imgFilename) ; i = i + 1 if lsImages: return lsImages return {"error" : "File not found!"}
前端Vuetify代码
卡片组件模板
<v-card> <v-subheader>Output Images</v-subheader> <v-container fluid grid-list-md > <v-layout row wrap> <v-flex v-for="card0 in cards" :key="card0.title" v-bind="{ [`xs${card0.flex}`]: true }" > <v-card elevation="10"> <v-img :src="card0.src" height="175px" > </v-img> <v-card-title class="text-h6" v-text="card0.title"></v-card-title> </v-card> </v-flex> </v-layout> </v-container> </v-card>
请求处理方法
onUploadSelectedFileClick () { axios({ method: 'get', url: `${apiUrl}/api/v1/img/download`, responseType: 'stream' }) .then(response => { const imgSearches = response.data; let i = 0 var jInput = this.iInput * 4; for (const file of imgSearches) { if (jInput > i) { Vue.set(this.cards, i, {title: file.filename, src: file.path, flex: 3 }); i++ } }; }) .catch(error => { console.error(error); }); }
问题原因分析
- 后端返回格式无效:
download_images接口返回FileResponse对象列表,FastAPI无法将多个FileResponse序列化为前端可解析的JSON。前端拿到的file.path是服务器本地路径,浏览器无法直接访问服务器本地文件系统。 - 前端请求类型错误:设置
responseType: 'stream'不符合需求,实际需要的是可解析的JSON数据而非流格式。
解决方案
方案一:返回图片访问URL(推荐)
通过FastAPI挂载静态文件目录,让前端直接通过URL加载图片。
后端修改
from fastapi.staticfiles import StaticFiles # 挂载图片目录为静态资源,前端可通过/static/文件名访问 app.mount("/static", StaticFiles(directory=DOWNOAD_PATH), name="static") @router.get('/img/download') async def download_images(): lsImages = [] for imgFilename in os.listdir(DOWNOAD_PATH): file_path = os.path.join(DOWNOAD_PATH, imgFilename) if os.path.isfile(file_path): # 生成前端可访问的图片URL img_url = f"/static/{imgFilename}" lsImages.append({"filename": imgFilename, "url": img_url}) return lsImages if lsImages else {"error": "File not found!"}
前端修改请求方法
onUploadSelectedFileClick () { axios.get(`${apiUrl}/api/v1/img/download`) .then(response => { const imgSearches = response.data; let i = 0 const jInput = this.iInput * 4; for (const file of imgSearches) { if (jInput > i) { Vue.set(this.cards, i, {title: file.filename, src: file.url, flex: 3 }); i++ } }; }) .catch(error => { console.error(error); }); }
方案二:返回Base64编码图片
将图片转为Base64字符串返回,前端直接用该字符串作为图片源。
后端修改
import base64 def image_to_base64(file_path): with open(file_path, "rb") as f: return base64.b64encode(f.read()).decode('utf-8') @router.get('/img/download') async def download_images(): lsImages = [] for imgFilename in os.listdir(DOWNOAD_PATH): file_path = os.path.join(DOWNOAD_PATH, imgFilename) if os.path.isfile(file_path): base64_str = image_to_base64(file_path) img_src = f"data:image/jpg;base64,{base64_str}" lsImages.append({"filename": imgFilename, "src": img_src}) return lsImages if lsImages else {"error": "File not found!"}
前端修改请求方法
onUploadSelectedFileClick () { axios.get(`${apiUrl}/api/v1/img/download`) .then(response => { const imgSearches = response.data; let i = 0 const jInput = this.iInput * 4; for (const file of imgSearches) { if (jInput > i) { Vue.set(this.cards, i, {title: file.filename, src: file.src, flex: 3 }); i++ } }; }) .catch(error => { console.error(error); }); }
内容的提问来源于stack exchange,提问作者GebetX
相关产品推荐
相关产品推荐

