24

Django 中是否有现有的 HTTP 字节范围实现?即,当客户端发送 Range: 标头时,我希望我的 Django 应用程序接受它并回复 HTTP“206 Partial Content”响应。

我可以从头开始写一些东西,但肯定有人已经这样做了?

这有不同的部分:

  1. 解析和完整性检查 Range 标头
  2. 实际生成范围
  3. 支持在响应中返回单个范围
  4. 支持在单个响应中返回多个范围,经过适当的 MIME 编码

当然至少(1)和(4)在某处有图书馆支持?

4

4 回答 4

11

这是一些适用于 Django 1.11+ 的基本中间件代码。它只处理一个范围,但这就是我个人所需要的。

import os

from django.utils.deprecation import MiddlewareMixin


class RangesMiddleware(MiddlewareMixin):
    def process_response(self, request, response):
        if response.status_code != 200 or not hasattr(response, 'file_to_stream'):
            return response
        http_range = request.META.get('HTTP_RANGE')
        if not (http_range and http_range.startswith('bytes=') and http_range.count('-') == 1):
            return response
        if_range = request.META.get('HTTP_IF_RANGE')
        if if_range and if_range != response.get('Last-Modified') and if_range != response.get('ETag'):
            return response
        f = response.file_to_stream
        statobj = os.fstat(f.fileno())
        start, end = http_range.split('=')[1].split('-')
        if not start:  # requesting the last N bytes
            start = max(0, statobj.st_size - int(end))
            end = ''
        start, end = int(start or 0), int(end or statobj.st_size - 1)
        assert 0 <= start < statobj.st_size, (start, statobj.st_size)
        end = min(end, statobj.st_size - 1)
        f.seek(start)
        old_read = f.read
        f.read = lambda n: old_read(min(n, end + 1 - f.tell()))
        response.status_code = 206
        response['Content-Length'] = end + 1 - start
        response['Content-Range'] = 'bytes %d-%d/%d' % (start, end, statobj.st_size)
        return response

像这样安装它settings.py

MIDDLEWARE_CLASSES = [
    'path.to.RangesMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
]
于 2016-03-10T21:50:03.617 回答
10

这是两个相关的功能请求(一个是开放的,另一个是第一个的副本):

这两个问题都基于Google Group 的讨论

由于架构问题,票处于“挂起”状态,并且对于这是否真的是 Django 应该支持的东西没有达成共识。主要是因为网络服务器能够提供字节服务。

如果您仍然对实现感兴趣,则发送了一个尚未审查的补丁,实现了一个特殊的RangedFileReader类,用于使用 以块的形式返回响应,StreamingHttpResponse对标头进行解析和完整性检查HTTP_RANGE

您可以试用 fork 或使用该解决方案作为您自己的基础。

仅供参考,这里进行了另一次尝试- 它还没有完成,但对审查很有用。


要解析Range标头,请参阅:

于 2014-12-26T21:30:11.717 回答
3

关于内容范围的三种方法

根据你的情况选择合适的。

1.支持所有动态视图和静态文件

WhiteNoise提供了一个中间件来支持全局设置。

2. 只支持静态文件

Nginx 可以支持静态和媒体文件。

请参阅使用 uWSGI 和 nginx 设置 Django 和您的 Web 服务器的更多详细信息。如果某些视图需要重定向到静态或媒体文件,请参阅stackoverflow 答案

3. 只支持特定的动态视图

Django Ranged Response支持具有内容范围的响应。将此响应用于您想要的每个视图。这些视图主要是为媒体 API 设计的,例如语音合成、视频生成器。


声明:我是 Django Ranged Response 的贡献者。但我认为使用 WhiteNoise 最容易维护。

于 2017-07-19T02:43:10.557 回答
0

如果您只是在测试中需要它并且不介意nginx在您面前运行django(它有很多其他优点,如分块等),那么您可以添加proxy_force_ranges on;http/server/location,例如,修复诸如 Chrome 之类的问题要求它能够在视频中搜索(通过设置video.currentTime)等。

于 2021-01-20T03:38:07.640 回答