关于http:从Django提供压缩后的内容

Serving gzipped content from django

我正在尝试在Django中提供文本/ html页面的压缩版本,但是Firefox告诉我内容编码错误。

笔记:

  • 我意识到这不是最佳做法,因此我很可能会使用mod_gzip。 这只是一个学习练习,可以了解正在发生的事情。
  • 我知道Django gzip中间件-二进制文件有问题。

这是我的代码:

1
2
3
4
5
6
rendered_page =  zlib.compress(template.render(context).encode('utf-8'))

response = HttpResponse(rendered_page)
response['Content-Encoding'] = 'gzip'
response['Content-Length'] = len(rendered_page)
return response

我在这里想念什么吗? 内容长度是否有可能错误? 我还有其他标题吗?

谢谢。


您也可以简单地使用Django的GZip中间件:

通过添加以下内容来启用settings.py中的中间件:

1
2
3
4
MIDDLEWARE_CLASSES = (
    django.middleware.gzip.GZipMiddleware,
    ...
)

或者在返回特定响应之前执行此操作。在您的views.py中,dec将是某个网址的处理程序

1
2
3
4
5
6
7
8
from django.middleware.gzip import GZipMiddleware

gzip_middleware = GZipMiddleware()

 def dec(request, *args, **kwargs):
        response = func(request, *args, **kwargs)
        return gzip_middleware.process_response(request, response)
        return dec

注意:在使用GZip中间件之前,您应该确定自己不会受到旁道攻击。

Warning

Security researchers recently revealed that when compression
techniques (including GZipMiddleware) are used on a website, the site
may become exposed to a number of possible attacks. Before using
GZipMiddleware on your site, you should consider very carefully
whether you are subject to these attacks. If you’re in any doubt about
whether you’re affected, you should avoid using GZipMiddleware. For
more details, see the the BREACH paper (PDF) and breachattack.com.

也:

Changed in Django 1.10: In older versions, Django’s CSRF protection
mechanism was vulnerable to BREACH attacks when compression was used.
This is no longer the case, but you should still take care not to
compromise your own secrets this way.


如果要对单个页面进行gzip压缩,而不是对所有页面进行gzip压缩,则可以使用gzip_page装饰器代替GzipMiddleware。

1
2
3
4
5
from django.views.decorators.gzip import gzip_page

@gzip_page
def viewFunc(request):
  return HttpResponse("hello"*100)

此处参考:https://docs.djangoproject.com/en/1.4/topics/http/decorators/#module-django.views.decorators.gzip


为此,zlib有点太低了。这是GZip中间件本身的工作方式(请参见django.utils.text.py中的compress_string):

1
2
3
4
5
6
7
8
9
10
11
import cStringIO, gzip
zbuf = cStringIO.StringIO()
zfile = gzip.GzipFile(mode='wb', compresslevel=6, fileobj=zbuf)
zfile.write(template.render(context).encode('utf-8'))
zfile.close()

compressed_content = zbuf.getvalue()
response = HttpResponse(compressed_content)
response['Content-Encoding'] = 'gzip'
response['Content-Length'] = str(len(compressed_content))
return response

GZip使用zlib,但zlib自己生成的内容对浏览器而言未正确编码,将" gzip"视为内容编码。希望有帮助!


如果您只需要一个页面,并且正在使用基于类的视图,请使用以下命令:

1
2
3
4
5
6
7
gzip_middleware = GZipMiddleware()

class GZipMixin(object):

    def dispatch(self, request, *args, **kwargs):
        response = super(GZipMixin, self).dispatch(request, *args, **kwargs)
        return gzip_middleware.process_response(request, response)

然后在您的实际视图中:

1
2
3
class MyView(GZipMixin, View):
    def get(self, request, *args, **kwargs):
         #return your response

如果使用zlib压缩数据,则必须将Content-Encoding设置为deflate,而不是gzip

1
2
3
4
5
6
rendered_page =  zlib.compress(template.render(context).encode('utf-8'))

response = HttpResponse(rendered_page)
response['Content-Encoding'] = 'deflate'
response['Content-Length'] = len(rendered_page)
return response

Content-Encoding

(...)

deflate

Using the zlib structure (defined in RFC 1950) with the deflate compression algorithm (defined in RFC 1951).


为了让其他人找到这个问题以及谁正在使用nginx,这个SO为我工作:

https://stackoverflow.com/a/41820704/4533488

基本上在/etc/nginx/nginx.conf文件中打开gzip对我来说完成了所有压缩处理。在客户端,大多数现代浏览器在接收到数据时会自动处理提取(解压缩)数据的功能,太好了!

这是nginx.conf文件设置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    http {

        #... other settings ...#

        ##
        # Gzip Settings
        ##

        gzip on;
        gzip_disable"msie6";

        gzip_vary on;
        gzip_proxied any;
        gzip_comp_level 6;
        gzip_buffers 16 8k;
        gzip_http_version 1.1;
        gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
    }