Vue3无法渲染Django REST API返回的图片问题求助
问题根源
核心问题是Axios默认以JSON格式处理响应,但图片是二进制数据,你直接把整个Axios响应对象赋值给image,img标签的src无法识别这个对象,所以显示灰色占位框。另外模板里的this.image写法也不符合Vue模板规范,模板中不需要加this。
前端(Vue 3)修复方案
修改getImage方法,让Axios正确处理二进制图片数据,再转换成浏览器能识别的URL格式:
<script setup> </script> <script> import axios from "axios"; export default { name: "SongBox", props: ['song'], methods: { async getImage() { try { // 关键配置:告诉Axios处理二进制blob数据 const response = await axios.get(this.$hostname + 'img?id=' + this.song.pk, { responseType: 'blob' }); // 将Blob转换成可直接用于src的Object URL this.image = URL.createObjectURL(response.data); } catch (error) { // 请求失败时设置默认占位图(可替换成你的默认图路径/base64) this.image = ''; } } }, created() { this.getImage() }, beforeUnmount() { // 组件销毁时释放Object URL,避免内存泄漏 if (this.image) { URL.revokeObjectURL(this.image); } }, data() { return { image: '' // 初始化为空字符串,避免无效src导致占位 } } } </script> <template> <div v-if="song" class="flex w-1/3 flex-wrap px-3 -mb-12"> <div class="w-full px-2"> <div class="relative overflow-hidden bg-cover bg-no-repeat" style="background-position: 50%"> <!-- 去掉this,直接使用image变量 --> <img class="block w-full h-full rounded-lg object-cover object-center" :src="image" alt="专辑封面"/> <div class="absolute rounded-lg bottom-0 right-0 left-0 top-0 h-full w-full bg-black bg-fixed opacity-50 overflow-hidden"></div> </div> <div class="relative inset-y-[-20%] bottom-5 hidden py-5 text-center text-white md:block"> <p class="text-xl">{{ song.fields.song_name }}</p> <p class="text-base">{{ song.fields.song_artist }}</p> </div> </div> </div> </template>
后端(Django REST)优化建议
你的后端代码存在冗余和潜在报错风险(比如直接取request.GET['id']会触发KeyError),可以优化为更健壮的版本:
from django.http import FileResponse, HttpResponseNotFound from rest_framework.decorators import api_view from .models import Song import os @api_view(['GET']) def img_api(request): song_id = request.GET.get('id') # 处理id为空或undefined的情况 if not song_id or song_id == 'undefined': return HttpResponseNotFound(content_type='application/json') song = Song.objects.filter(song_id=song_id).first() if not song: return HttpResponseNotFound(content_type='application/json') img_path = os.path.join(SONG_PATH, song.song_image_file) try: # 根据后缀返回对应Content-Type if song.song_image_file.endswith(".png"): return FileResponse(open(img_path, 'rb'), content_type='image/png') else: return FileResponse(open(img_path, 'rb'), content_type='image/jpeg') except (FileNotFoundError, PermissionError): return HttpResponseNotFound(content_type='application/json')
额外提示
- 可以给
img标签加v-if="image",或者用骨架屏占位,避免初始阶段显示灰色框。 - 务必在组件销毁时调用
URL.revokeObjectURL释放资源,防止内存泄漏。
内容的提问来源于stack exchange,提问作者thenordwrath
相关产品推荐
相关产品推荐

