Enabling compression on Heroku using python

前端 未结 1 1145
北海茫月
北海茫月 2021-02-14 01:08

Google now penalizes due to not being so mobile friendly. So in an effort to make things better, it recommends I compress a lot of my Javascript with Gzip or Deflate. I\'ve seen

1条回答
  •  谎友^
    谎友^ (楼主)
    2021-02-14 02:00

    Bottom Line Up Front - It's going to depend on the details of your app... Flask? Django? uWSGI? whitenoise and gunicorn seem to be the "go to" frameworks on Heroku, so that's what I used in the example below. It should translate to other frameworks.

    Explication - The gist of the Google recommendation is about minimizing the number of bytes physically transferred from the server. There are several ways to do this, but among the highest impact, in no particular order -

    • Minify JavaScript and CSS
    • Merge those files together
    • Manipulate cache behavior
    • Compress the HTTP response body

    The quoted recommendation deals with that last bit, and it's important to understand that compressing the response body is part of "content negotiation" in the HTTP specification - the browser doesn't just ask for a particular resource via the URL; it also provides hints about its preferred representation of that resource, e.g., what content type, how it's encoded, can it be sent in multiple "chunks", etc.

    Thus, ideally, the layer of the application that handles HTTP should handle this particular task. In a typical application stack, that would mean a web server like Apache or nginx, in which the web server will proxy requests for specific, dynamic paths to your web framework, and handle the "static" content directly.

    In Heroku, however, the HTTP layer is split between the platform itself and your application - the "routing mesh" acts as a reverse proxy, handling basic HTTP and HTTPS and enhancing the requests by injecting headers with proxy information, for example; everything else is up to your app. However, your "app" is fairly constrained, since you don't have free-reign to install nginx, etc.

    Most web frameworks (Django, Flask, Rails, Play!, etc. etc.) are highly generalized, and can work in conjunction with an external web server (recommended for production) or can work independently, providing their own, usually lightweight web servers (recommended for development). The frameworks also pair well with "containers" that provide both the run-time environment for the application and the heavy lifting at the HTTP layer (uWSGI, Gunicorn, Rack, etc.)

    This is the option to go for with Heroku. Although I have the most experience with uWSGI, the example below is for Flask + Gunicorn + WhiteNoise (the preferred library for serving static files on Heroku in Python). Note that WhiteNoise also works with Django, so adapting this should be trivial, should Django be your framework of choice. So, all that exposition results in two pretty simple steps to get started:

    • Add whitenoise to your requirements.txt
    • Modify the WSGI application to have WhiteNoise "wrap" your application.

    For example:

    from flask import Flask
    from whitenoise import WhiteNoise
    
    flapp = Flask(__name__)
    #use a subdirectory for root, otherwise, the actual .py files can be served...
    app = WhiteNoise(flap, root='./static/')
    
    #define your routes:
    @flapp.route('/')
    def home_page():
        #etc. etc.
    

    This will get you gzip'd content if the client sends an "Accept-Encoding: gzip" header. There are many, many other levers and knobs to pull and tweak, but this is a starting point. Eventually, you'll worry about CPU overhead and want to pre-compress the files; or you may decide that off-loading static files is the way to go.

    To verify, use a tool like cURL to grab a static file:

    curl -i -H "Accept-Encoding: gzip" http://yourapp.herokuapp.com/path/to/static
    

    The -i flag should print out headers, which will show you the details of how the request was served. Note the `Content-Encoding

    HTTP/1.1 200 OK
    Connection: keep-alive
    Server: gunicorn/19.3.0
    Date: Wed, 20 May 2015 15:33:35 GMT
    Last-Modified: Wed, 20 May 2015 15:26:06 GMT
    Content-Type: text/html; charset="utf-8"
    Cache-Control: public, max-age=60
    Access-Control-Allow-Origin: *
    Vary: Accept-Encoding
    Content-Encoding: gzip
    Content-Length: 662
    Via: 1.1 vegur
    

    Hope this helps...

    0 讨论(0)
提交回复
热议问题