You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何缓存Django REST Framework的HTTP流式响应?

缓存Django REST Framework流式HTTP响应的问题

我正在尝试缓存Django REST Framework的HTTP流式响应,思路是继承StreamingHttpResponse子类,在流式传输时把响应块写入临时文件,等流式传输完成并关闭后,调用可调用对象将文件复制到缓存中。

实现代码如下:

from django.http import StreamingHttpResponse
from tempfile import TemporaryFile

class CachedStreamingHttpResponse(StreamingHttpResponse):

    def __init__(self, streaming_content=(), *args, **kwargs):
        self._post_render_callbacks = []
        self._buffer = None
        self.buffered = False
        super().__init__(streaming_content, *args, **kwargs)

    def _set_streaming_content(self, value):
        self._buffer = TemporaryFile()
        super()._set_streaming_content(value)

    def post_render(self):
        self._buffer.seek(0)
        self.buffered = self._buffer
        retval = self
        for post_callback in self._post_render_callbacks:
            newretval = post_callback(retval)
            if newretval is not None:
                retval = newretval

    def buffer(self, b):
        self._buffer.write(b)
        return b

    @staticmethod
    def closing_iterator_wrapper(iterable, close):
        try:
            yield from iterable
        finally:
            close()

    @property
    def streaming_content(self):
        buffered = map(self.buffer, super().streaming_content)
        return self.closing_iterator_wrapper(buffered, self.post_render)

    @streaming_content.setter
    def streaming_content(self, value):
        self._set_streaming_content(value)

    def add_post_render_callback(self, callback):
        """A list of callables to be run after the final chunk is returned. Used to copy the response to cache."""
        if self.buffered:
            callback(self)
        else:
            self._post_render_callbacks.append(callback)

我原本计划让缓存框架向该响应传入一个可调用对象,在streaming_content的finally块中调用它,把临时文件复制到S3。但使用上述代码时出现了两个流(一个压缩、一个未压缩),导致响应无法从缓存中返回。

我已经修正了代码中的语法错误,其中一个关键点需要注意:因为重写了streaming_content的getter,必须重新声明和父类完全一致的setter。

注:缓存流式响应几乎总是不合理的。但这些响应由复杂查询、DRF序列化器和视图集生成,我们采用流式传输是为了让网络条件极差的用户更快看到数据。流式传输会在整个过程中占用服务器和客户端资源,可能比不流式传输消耗更多资源;它可能将部分内存消耗转移到数据库(通过游标读取记录)。响应大小最多几MB,通常更小,将被缓存到我们的S3缓存层,Redis成本过高。

内容的提问来源于stack exchange,提问作者Chris

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 21:17:43