Django的Byte Ranges

时间:2013-01-14 18:22:33

标签: django http http-headers

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

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

这有很多部分:

  1. 检查Range标题
  2. 的解析和健全性
  3. 实际生成范围
  4. 支持在回复中返回单个范围
  5. 支持在单个响应中返回多个范围,适当地使用MIME编码
  6. 当然至少(1)和(4)在哪里有图书馆支持?

4 个答案:

答案 0 :(得分:8)

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

这两个问题都基于Google Group discussion

由于架构问题,故障单处于“悬挂”状态,因为对于这是否真的是Django应该支持的内容尚未达成共识。主要是因为Web服务器能够进行字节服务。

如果您仍然对实现感兴趣,则会发送一个尚未审核的补丁,该补丁实现了一个特殊的RangedFileReader类,用于使用StreamingHttpResponse以块的形式返回响应,有解析和健全性检查HTTP_RANGE标题:

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

仅供参考,还有另一次尝试here - 它没有完成,但可以查看。


要解析Range标题,请参阅:

答案 1 :(得分:3)

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

import os

try:
    from django.utils.deprecation import MiddlewareMixin
except ImportError:  # django < 1.10
    MiddlewareMixin = object


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',
]

答案 2 :(得分:2)

关于内容范围的三个方法

根据您的情况选择合适的一个。

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

WhiteNoise提供了支持全局设置的中间件。

2。仅支持静态文件

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

查看有关Setting up Django and your web server with uWSGI and nginx的更多详情。如果某些视图需要重定向到静态或媒体文件,请参阅the stackoverflow answer

3。仅支持特定的动态视图

Django Ranged Response支持包含内容范围的回复。对您想要的每个视图使用此响应。这些视图主要是为媒体API而设计的,如语音合成,视频生成器。

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

答案 3 :(得分:0)

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