我们知道有HTTP Range规范,这里mozilla对此规范做了详细的解释。
前端的<video>
标签会自动在请求头部分添加Range: bytes=0-
或者其他的范围。
IOS浏览器内核默认也会在请求头部分添加Range,如果视频后端不支持HTTP Range规范则无法正常播放,IOS浏览器无法播放视频可在这个问题上排查。
我们需要根据这个规范在后端解析Range请求头,并返回请求头对应的文件分片,且服务器响应状态码为206。
下面是Sanic实现的完整代码,并写了注释,用Java等其他语言实现的话,逻辑是一样的。文章来源:https://www.toymoban.com/news/detail-654554.html
(有一个疑问的就是Sanic里面的源码应该是实现了HTTP Range规范的,不知道为什么直接调用会出错,有大佬交流下吗)文章来源地址https://www.toymoban.com/news/detail-654554.html
from sanic import Sanic, response
from sanic.response import json
from sanic.response.types import HTTPResponse, JSONResponse, ResponseStream
from mimetypes import guess_type
from sanic.compat import Header, open_async, stat_async
from sanic.response import file_stream
from urllib.parse import quote, unquote
import os
app = Sanic("private-web")
def parse_range_header(range_header, file_size):
# 解析Range参数
start, end = range_header.split('=')[1].split('-')
start = int(start)
end = int(end) if end else file_size - 1
# 确保范围在文件大小范围内
start = min(max(start, 0), file_size - 1)
end = min(end, file_size - 1)
return start, end
@app.route('/video/<vid:str>')
async def videoRange(request, vid):
# 网址中文转码
vid = unquote(vid)
# 视频路径
file_path = f"{vid}.mp4"
# 获取文件大小
file_size = os.path.getsize(file_path)
# 获取请求头Range参数
range_header = request.headers.get("Range")
headers = {}
if range_header:
# 解析Range参数
start, end = parse_range_header(range_header, file_size)
status = 206
headers["Content-Range"] = f"bytes {start}-{end}/{file_size}"
headers['Content-Length'] = str(end - start + 1)
chunk_size: int = 4096
mime_type = None
mime_type = mime_type or guess_type(file_path)[0] or "text/plain"
# 这段代码就是拿 file_stream 里的源码改的,直接使用file_stream总是报错,有大佬帮忙解释并实现下吗
async def _streaming_fn(response):
async with await open_async(file_path, mode="rb") as f:
await f.seek(start)
to_send = end - start + 1
while to_send > 0:
content = await f.read(min((to_send, chunk_size)))
if len(content) < 1:
break
to_send -= len(content)
await response.write(content)
return ResponseStream(
streaming_fn=_streaming_fn,
status=status,
headers=headers,
content_type=mime_type,
)
else:
return await file_stream(file_path, headers=headers)
if __name__ == '__main__':
app.run(host='0.0.0.0')
到了这里,关于Sanic 实现 HTTP Range,解决前端视频无法拖动问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!