3

在我的 Django 应用程序的 views.py 中,我在尝试设置以下 HTTP 标头字段后返回一个 HttpResponse 对象:

# Create a Response Object with the content to return 
response = HttpResponse("%s"%(output_display),mimetype='text/html')
response['Cache-Control'] = 'must-revalidate, max-age=20'
response['Vary'] = 'Accept-Encoding'
response['Transfer-Encoding'] = 'gzip'
#response['Content-Encoding'] = 'gzip'
response['Connection'] = 'close'
#response['Content-Type'] = 'text/html'
response['Content-Length'] = '%s'%(len(output_display))
return response

然后我使用带有 FireFox 的 Live HTTP Headers 插件捕获输出,它看起来像:

HTTP/1.1 200 OK
Date: Sun, 10 Mar 2013 14:55:09 GMT
Server: Apache/2.2.22 (Ubuntu)
Transfer-Encoding: gzip, chunked   <---------- Why 'chunked'?
Vary: Accept-Encoding
Connection: close
Cache-Control: must-revalidate, max-age=20
Content-Encoding: gzip
Content-Type: text/html <---------------------- No Content-Length even though I set it?
X-Pad: avoid browser bug

我正在尝试使用 Apache2 的 mem_cache 进行缓存,因此我需要设置 Content-Length 并且不能为 Transfer-Encoding 设置“分块”。

我的 Apache2 mem_cache.conf 看起来像(大量仅用于测试):

<IfModule mod_mem_cache.c>
        CacheEnable mem /
        MCacheSize 10000
        MCacheMaxObjectCount 10000000
        MCacheMinObjectSize 1
        MCacheMaxObjectSize 10000000
        MCacheMaxStreamingBuffer 10000000
</IfModule>

但是,即使我在响应代码中明确设置了 Content-Length 和 Transfer-Encoding ,也会自动插入“chunked”,因此我的 Content-Length 不会受到尊重。为什么是这样?如何解决此问题以获得所需的响应?谢谢 -

4

1 回答 1

1

我最近在 mod_wsgi 应用程序中遇到了类似的问题;我试图更新使用其内置磁盘缓存的 apache 配置,以改用 socache/memcache。

磁盘缓存工作正常,但切换到 memcache 或 shmcb 不起作用。如果我对想要缓存的资源发出请求,它不会将其存储在缓存中(CacheDetailHeader对此很有帮助)。在调试时检查日志,我发现了以下消息:

[Wed Dec 05 18:52:16.571002 2018] [cache_socache:debug] \
[pid 884:tid 140422596777728] mod_cache_socache.c(389): \
[client 127.0.0.1:56576] AH02346: URL 'http://127.0.1.1:80/cacheme/c?' \
had no explicit size, ignoring, referer: http://127.0.0.1/

socache 似乎不喜欢没有明确大小的对象。我尝试将这些 mod_memcache 设置的较新的 socache 等效项设置为足够大的值:CacheSocacheMaxSizeCacheSocacheReadSize.

我知道Content-Length标题已被设置并到达某个地方;当我故意计算错误时,它出现在 mod_wsgi 日志中。

我发现了一些东西:

  1. 不要Transfer-Encoding自己设置标头,因为 WSGI 规范禁止这样做:

    谁设置了 Transfer-Encoding: chunked header?

  2. 即使您Content-Length自己设置标题,它也被 apache 压缩。这会改变长度;当 Apache 不知道长度是多少时,它会切换到分块并删除Content-Length标题。

我发现:

  • Content-Type: text/html

  • Content-Length设置为我的 utf-8 编码大小

在 python/mod_wsgi 应用程序中设置,并且:

  • SetEnv no-gzip 1

在 apache 配置中设置,该对象使其进入 shmcb 缓存。

看起来当 apache gzip 压缩一个对象时,它将标头更改为它不被 socache 接受。

我四处寻找使它们兼容的方法,但在这个问题上找不到太多。在 mod_cache 文档中提到了重新排序缓存/放气过滤器:

https://httpd.apache.org/docs/2.4/mod/mod_cache.html#finecontrol

如果我输入一个指令来重新排序缓存/放气过滤器,这将起作用:

# within a directory
SetOutputFilter CACHE;DEFLATE

奇怪的是,在缓存未命中时,服务器返回 gzip 压缩的内容,但在缓存命中时,服务器返回未编码的 text/html。这看起来很奇怪,但我对 FilterChain 指令的理解还不够好,无法尝试这些指令。

我还在 php/content-length 的相关问题中发现了一些提及:

https://serverfault.com/questions/183843/content-length-not-sent-when-gzip-compression-enabled-in-apache

那里的答案发现,如果他们将 设置为DeflateBufferSize足够大的值,则将设置内容长度。

我无法让它工作。

所以看起来有人在选择缓存或压缩之间陷入困境。

于 2018-12-06T00:33:21.177 回答