Serving gzipped content from django

2019-03-08 08:08发布

问题:

I'm trying to serve a gzipped version of a text/html page in Django, but Firefox is telling me there's a content encoding error.

NOTES:

  • I realize this is not a best practice and I'm most likely going to use mod_gzip. This is just a learning exercise to understand what's going on.
  • I know about the Django gzip middleware-- it has problems with binary files.

Here's my code:

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

Am I missing something here? Is it possible that the content length is wrong? Are there additional headers I'm missing?

Thanks.

回答1:

zlib is a bit too low-level for this purpose. Here's how the GZip middleware itself does it (see compress_string in django.utils.text.py):

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 uses zlib, but on its own zlib produces content that's improperly encoded for a browser seeing 'gzip' as the content encoding. Hope that helps!



回答2:

You could also simply use django's gzip middleware:

Either by enabling the middleware in settings.py by adding:

MIDDLEWARE_CLASSES = (
 django.middleware.gzip.GZipMiddleware,
...

)

Or do it before you return a particular response. In your views.py, dec would be the handler for a certain url

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


回答3:

If you're gzipping single page, not for all pages, you can use gzip_page decorator instead of GzipMiddleware.

from django.views.decorators.gzip import gzip_page

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

Reference here: https://docs.djangoproject.com/en/1.4/topics/http/decorators/#module-django.views.decorators.gzip



回答4:

If you need it for a single page and you are using class based views, use this:

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)

Then in your actual view:

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


回答5:

If you compress your data with zlib, you have to set Content-Encoding to deflate, not gzip.

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).



回答6:

For the sake of others finding this question and who are using nginx, this SO worked for me:

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

Basically turning gzip on in the /etc/nginx/nginx.conf file did all the compression handling for me. On the client-side, most modern browsers automatically handle extracting (uncompressing) the data when receiving it - sweet!

Here is the nginx.conf file settings:

    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;
    }


标签: django http gzip