简体   繁体   English

如何在 Python 中使用 Flask 压缩/最小化 JSON/Jsonify 的大小?

[英]How to compress/minimize size of JSON/Jsonify with Flask in Python?

I'm sending a huge JSON string (with jsonify in Flask) to my webpage pretty often, so I would like to reduce the data.我经常向我的网页发送一个巨大的 JSON 字符串(在 Flask 中使用 jsonify),所以我想减少数据。 The easiest option is probably to remove all line breaks and space characters, but just to give you an example of this:最简单的选择可能是删除所有换行符和空格字符,但只是给你一个例子:

Normal jsonify: 361KB普通 jsonify:361KB
Removing all line breaks and space characters: 118KB (wow).删除所有换行符和空格字符:118KB(哇)。
Zip the original file: 35KB (double wow).压缩原始文件:35KB(双哇)。

So I basically wonder if there is an easy way to come close to the 35KB.所以我基本上想知道是否有一种简单的方法可以接近 35KB。 I couldn't find a solution so far which I could easily implement in python and javascript (to decompress).到目前为止,我找不到可以在 python 和 javascript 中轻松实现(解压缩)的解决方案。

Right now, I send around 4-5MB of data every second, which is - you guessed right - a "little bit" too much.现在,我每秒发送大约 4-5MB 的数据,这 - 你猜对了 - “一点点”太多了。

Old question but I was searching for this and it was the first result on Google.老问题,但我正在搜索这个,这是谷歌上的第一个结果。 The link to the answer of Leon has a solution not for Flask and also it is old. Leon 的答案链接有一个不适用于 Flask 的解决方案,而且它也很旧。 With Python 3 now we can do all in few lines with the standard libraries (and Flask):现在使用 Python 3,我们可以使用标准库(和 Flask)在几行代码中完成所有工作:

from flask import make_response, json
import gzip

@app.route('/data.json')
def compress():
    very_long_content = [{'a': 1, 'b': 2}, {'c': 3, 'd': 4}]
    content = gzip.compress(json.dumps(very_long_content).encode('utf8'), 5)
    response = make_response(content)
    response.headers['Content-length'] = len(content)
    response.headers['Content-Encoding'] = 'gzip'
    return response

With gzip.compress we have directly a byte string compressed and it is required as input a byte string.使用gzip.compress我们直接压缩了一个字节字符串,它需要一个字节字符串作为输入。 Then, as the link from Leon, we make a custom response saying that the content is a gzip so the browser will decompress by itself.然后,作为来自 Leon 的链接,我们进行了自定义响应,说明内容是 gzip,因此浏览器将自行解压缩。

For decoding in Javascript using a JQuery ajax request there isn't any particular difference from a standard request:对于使用 JQuery ajax 请求在 Javascript 中解码,与标准请求没有任何特别的区别:

$.ajax({
    url: '/data.json',
    dataType: 'json',
    success: function(data) {
        console.log(data);
    }
})

Note that this snippet compress and then send the long content.请注意,此代码段压缩然后发送长内容。 You should consider the amount of time that it takes to compress the content (especially in this case that we have very long content), so be sure to set an appropriate level of compression that doesn't require more time to compress + send than send the long content as it is.您应该考虑压缩内容所需的时间(特别是在我们有很长的内容的情况下),因此请确保设置适当的压缩级别,压缩 + 发送所需的时间不会超过发送时间内容很长。

My use case was that I sent the big content from a slow connection, so I had all the benefits to compress the content before send it.我的用例是我从慢速连接发送大内容,所以我有所有的好处在发送之前压缩内容。

Web requests do support GZip and you could implement it in python. Web 请求确实支持 GZip,您可以在 python 中实现它。

Here is someone who asked that exact question.这是问那个确切问题的人。 How to use Content-Encoding: gzip with Python SimpleHTTPServer 如何使用 Content-Encoding: gzip 和 Python SimpleHTTPServer

According to the flask-compress repo根据烧瓶压缩回购

The preferred solution is to have a server (like Nginx) automatically compress the static files for you.首选的解决方案是让服务器(如 Nginx)自动为您压缩静态文件。

But you can do it in flask: https://github.com/colour-science/flask-compress .但是你可以在烧瓶中做到: https : //github.com/colour-science/flask-compress

If you go the gzip route you will not need to remove line breaks and white space, but if you still want to then according to the flask documentation you can disable pretty print by setting JSONIFY_PRETTYPRINT_REGULAR to false.如果您使用 gzip 路线,您将不需要删除换行符和空格,但是如果您仍然想要根据烧瓶文档,您可以通过将 JSONIFY_PRETTYPRINT_REGULAR 设置为 false 来禁用漂亮打印。

If you're looking for a library to help serve compressed content via Gzip (or Brotli), try flask-compress .如果您正在寻找一个库来帮助通过 Gzip(或 Brotli)提供压缩内容,请尝试flask-compress It's very simple;这很简单; this might be all you need to do:这可能就是您需要做的所有事情:

from flask import Flask
from flask_compress import Compress

app = Flask(__name__)
Compress(app)

Inspired by Ripper346's answer , but rather than manually writing it for all routes/views.Ripper346's answer 的启发,而不是为所有路线/视图手动编写它。 It is just better to add a snippet(compared to external dependency on a library), which will compress the response before sending it out.最好添加一个片段(与库的外部依赖相比),它将在发送之前压缩响应。

Add the following to your app file, or wherever suited(eg. gzip_compress.py):将以下内容添加到您的应用程序文件或任何适合的地方(例如 gzip_compress.py):

import gzip
from io import BytesIO
from flask import request

class GzipCompress:
    def __init__(self, app, compress_level=9, minimum_size=100):
        self.app = app
        self.compress_level = compress_level
        self.minimum_size = minimum_size
        self.app.after_request(self.after_request)

    def after_request(self, response):
        accept_encoding = request.headers.get('Accept-Encoding', '')

        if response.status_code < 200 or \
           response.status_code >= 300 or \
           response.direct_passthrough or \
           len(response.get_data()) < self.minimum_size or \
           'gzip' not in accept_encoding.lower() or \
           'Content-Encoding' in response.headers:
            return response

        gzip_buffer = BytesIO()
        gzip_file = gzip.GzipFile(mode='wb', 
                                  compresslevel=self.compress_level, 
                                  fileobj=gzip_buffer)
        gzip_file.write(response.get_data())
        gzip_file.close()
        response.set_data(gzip_buffer.getvalue())
        response.headers['Content-Encoding'] = 'gzip'
        response.headers['Content-Length'] = len(response.get_data())

        return response

And then in your app:然后在您的应用中:

from flask import Flask
from gzip_compress import GzipCompress

app = Flask(__name__)
GzipCompress(app)

You can set your gzip compression level and the minimum response size for compression to kick in. It includes other checks for gzip support and response codes.您可以设置 gzip 压缩级别和最小响应大小以进行压缩。它包括对 gzip 支持和响应代码的其他检查。

Spinoff of suvigyavijay's answer , without using awkward classes, io.BytesIO() , or gzip.GzipFile (he did a lot of heavy lifting though, props). suvigyavijay 的答案衍生,没有使用尴尬的类, io.BytesIO()gzip.GzipFile (尽管他做了很多繁重的工作,道具)。

Note.笔记。 This applies to all requests, I think.我认为这适用于所有请求。

import flask, gzip

app = flask.Flask(__name__)

@app.after_request
def compress(response):
  accept_encoding = flask.request.headers.get('accept-encoding','').lower()
  if response.status_code<200 or response.status_code>=300 or response.direct_passthrough or 'gzip' not in accept_encoding or 'Content-Encoding' in response.headers:  return response
  content = gzip.compress(response.get_data(), compresslevel=9)  # 0: no compression, 1: fastest, 9: slowest. Default: 9
  response.set_data(content)
  response.headers['content-length']   = len(content)
  response.headers['content-encoding'] = 'gzip'
  return response

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM