FastAPI流式传输S3存储桶视频至Vue.js时绑定播放器出错,求解决
解决FastAPI流式S3视频到Vue.js video-player的绑定问题
问题场景
我需要从FastAPI向Vue.js的video-player流式传输S3存储桶中的视频,但遇到了问题:FastAPI返回的流式响应无法绑定到video-player(该组件需要通过src属性加载视频)。我尝试的Vue代码如下:
async videoDownload() { var url = '/api/v1/docs/1955/video' const resp = await this.axios.get(url); console.log("Video is streaming live !!") this.videoOptions.sources[0].src = resp; this.showvideo = true },
问题根源
video-player的src属性需要的是可直接访问的资源URL,而不是axios返回的响应对象。浏览器会自动向该URL发起请求,并处理视频流式传输所需的范围请求(断点续传),当前写法完全绕开了浏览器的原生处理逻辑。
修复步骤
1. 调整FastAPI端实现(支持范围请求)
FastAPI必须返回支持范围请求的流式响应,否则视频无法正常播放(比如拖动进度条)。以下是完整的实现代码:
from fastapi import FastAPI, Request, Response, status from fastapi.responses import StreamingResponse import boto3 from botocore.exceptions import ClientError app = FastAPI() # 初始化S3客户端(建议用环境变量存储密钥,避免硬编码) s3_client = boto3.client( 's3', aws_access_key_id="你的AWS访问密钥", aws_secret_access_key="你的AWS私有密钥" ) @app.get("/api/v1/docs/{doc_id}/video") async def stream_video(doc_id: str, request: Request): bucket_name = "你的S3存储桶名称" # 替换成你的视频文件在S3中的路径规则 object_key = f"videos/{doc_id}.mp4" try: # 获取视频文件的元数据 obj_metadata = s3_client.head_object(Bucket=bucket_name, Key=object_key) total_length = obj_metadata['ContentLength'] content_type = obj_metadata.get('ContentType', 'video/mp4') # 处理浏览器的范围请求(实现断点续传) range_header = request.headers.get('range') if range_header: start, end = range_header.replace('bytes=', '').split('-') start = int(start) end = int(end) if end else total_length - 1 # 从S3获取指定范围的字节流 s3_stream = s3_client.get_object( Bucket=bucket_name, Key=object_key, Range=f'bytes={start}-{end}' )['Body'] response = StreamingResponse( s3_stream, status_code=status.HTTP_206_PARTIAL_CONTENT, media_type=content_type ) response.headers['Content-Range'] = f'bytes {start}-{end}/{total_length}' response.headers['Content-Length'] = str(end - start + 1) else: # 返回完整视频流 s3_stream = s3_client.get_object(Bucket=bucket_name, Key=object_key)['Body'] response = StreamingResponse(s3_stream, media_type=content_type) response.headers['Content-Length'] = str(total_length) # 告诉浏览器支持范围请求 response.headers['Accept-Ranges'] = 'bytes' return response except ClientError: return Response(status_code=status.HTTP_404_NOT_FOUND)
2. 简化Vue端代码
直接将API的URL赋值给video-player的src,不需要用axios请求:
async videoDownload() { this.videoOptions.sources[0].src = '/api/v1/docs/1955/video'; this.showvideo = true; }
原理说明
浏览器的video元素会自动向指定的src URL发起请求,当需要流式播放时,会发送Range请求头。FastAPI端处理该请求后,返回对应范围的视频字节流,从而实现流畅的视频播放体验。
内容的提问来源于stack exchange,提问作者Shavej Shaikh
相关产品推荐
相关产品推荐

