因为后端返回的是视频的文件流,并不是视频文件地址。后端返回流的时候要为header设置一些参数,否则部分浏览器会出现问题(如Google Chrome...)。
django中常用返回文件流写法:
class VideoAPIView(APIView):
"""
视频视图
- 参数位置:
查询参数
- 请求参数:
- 路径参数:
- `id`: 文件id 必传
- 成功返回参数:
```
文件下载到本地
```
- 失败返回参数:
```
{
"rtCode": 0,
"rtMsg": "异常信息",
"rtData": ""
}
```
"""
def get(self, request, file_info_id):
try:
contents_post = {
"query": {
"match": {
"_id": file_info_id
}
},
"script": {
"source": "ctx._source['visits_nums'] = ctx._source['visits_nums']+1"
}
}
elasticsearch.update_by_query(index=constants.ELASTICSEARCH_INDEX, body=contents_post)
fileinfo_obj = models.FileInfo.objects.filter(file_info_id=file_info_id, delete_flag=FileInfo.DeleteFlagEnum.NOT_DELETE.value, file_type=FileInfo.FileTypeEnum.VIDEO.value)
video_name = fileinfo_obj.first().file_url
except models.FileInfo.DoesNotExist:
raise exceptions.ValidationError("数据不存在")
photo_path = constants.VIDEO_PATH
file_url_path = os.path.join(photo_path, video_name)
file_size = os.path.getsize(file_url_path)
response = FileResponse(open(file_url_path, 'rb'))
response['Content-Length'] = str(file_size)
response['Content-Type'] = 'application/octet-stream'
response['Content-Disposition'] = "attachment; filename={}".format(urlquote(video_name))
return response
这么写对于返回视频文件流,前端使用video标签展示时,就会出现部分浏览器无法拖动进度条快进问题。
解决:在返回的header中添加Content-Range和Accept-Ranges参数
class VideoAPIView(APIView):
"""
视频视图
- 参数位置:
查询参数
- 请求参数:
- 路径参数:
- `id`: 文件id 必传
- 成功返回参数:
```
文件下载到本地
```
- 失败返回参数:
```
{
"rtCode": 0,
"rtMsg": "异常信息",
"rtData": ""
}
```
"""
def get(self, request, file_info_id):
try:
contents_post = {
"query": {
"match": {
"_id": file_info_id
}
},
"script": {
"source": "ctx._source['visits_nums'] = ctx._source['visits_nums']+1"
}
}
elasticsearch.update_by_query(index=constants.ELASTICSEARCH_INDEX, body=contents_post)
fileinfo_obj = models.FileInfo.objects.filter(file_info_id=file_info_id, delete_flag=FileInfo.DeleteFlagEnum.NOT_DELETE.value, file_type=FileInfo.FileTypeEnum.VIDEO.value)
video_name = fileinfo_obj.first().file_url
except models.FileInfo.DoesNotExist:
raise exceptions.ValidationError("数据不存在")
photo_path = constants.VIDEO_PATH
file_url_path = os.path.join(photo_path, video_name)
file_size = os.path.getsize(file_url_path)
response = FileResponse(open(file_url_path, 'rb'))
response['Content-Length'] = str(file_size)
response['Content-Type'] = 'application/octet-stream'
response['Content-Range'] = f'bytes 0-{str(file_size)}/{str(file_size)}'
response['Accept-Ranges'] = 'bytes'
response['Content-Disposition'] = "attachment; filename={}".format(urlquote(video_name))
return response
关于Content-Range参数
用于响应头中,在发出带 Range 的请求后,服务器会在 Content-Range 头部返回当前接受的范围和文件总大小。一般格式:
Content-Range: bytes (unit first byte pos) - [last byte pos]/[entity legth]
例如:
Content-Range: bytes 0-499/22400
0-499 是指当前发送的数据的范围,而 22400 则是文件的总大小。
而在响应完成后,返回的响应头内容也不同:
HTTP/1.1 200 Ok(不使用断点续传方式)
HTTP/1.1 206 Partial Content(使用断点续传方式)