【问题标题】:How to compress/minimize size of JSON/Jsonify with Flask in Python?如何在 Python 中使用 Flask 压缩/最小化 JSON/Jsonify 的大小?
【发布时间】:2015-05-11 10:35:18
【问题描述】:

我经常向我的网页发送一个巨大的 JSON 字符串(在 Flask 中使用 jsonify),所以我想减少数据。最简单的选择可能是删除所有换行符和空格字符,但只是给你一个例子:

普通 jsonify:361KB
删除所有换行符和空格字符:118KB(哇)。
压缩原始文件:35KB(双哇)。

所以我基本上想知道是否有一种简单的方法可以接近 35KB。到目前为止,我找不到可以在 python 和 javascript 中轻松实现(解压缩)的解决方案。

现在,我每秒发送大约 4-5MB 的数据,这 - 你猜对了 - “一点点”太多了。

【问题讨论】:

    标签: javascript python json flask


    【解决方案1】:

    老问题,但我一直在寻找这个问题,这是 Google 上的第一个结果。 Leon 的答案的链接有一个不适用于 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
    

    使用gzip.compress,我们直接压缩了一个字节字符串,并且需要它作为输入一个字节字符串。然后,作为来自 Leon 的链接,我们做出自定义响应,说明内容是 gzip,因此浏览器将自行解压缩。

    对于使用 JQuery ajax 请求在 Javascript 中进行解码,与标准请求没有任何特别的区别:

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

    注意这个 sn -p 压缩然后发送长内容。您应该考虑压缩内容所需的时间(特别是在这种情况下,我们有很长的内容),因此请务必设置适当的压缩级别,压缩 + 发送不需要比发送更多的时间内容很长。

    我的用例是我通过慢速连接发送大内容,因此我可以在发送之前压缩内容。

    【讨论】:

    • 此外,我还在响应中添加了一个检查请求是否可以处理 gzip:if 'gzip' in request.headers.get('Accept-Encoding','').lower()
    • +1 检查以确保压缩时间实际上不会增加​​加载时间。我实现了这个,它实际上将加载时间增加了 200 毫秒!
    【解决方案2】:

    Web 请求确实支持 GZip,您可以在 python 中实现它。

    有人问了这个确切的问题。 How to use Content-Encoding: gzip with Python SimpleHTTPServer

    根据烧瓶压缩回购

    首选的解决方案是让服务器(如 Nginx)自动为您压缩静态文件。

    但你可以在烧瓶中做到这一点:https://github.com/colour-science/flask-compress

    如果您使用 gzip 路线,则不需要删除换行符和空格,但如果您仍想删除,则根据烧瓶文档,您可以通过将 JSONIFY_PRETTYPRINT_REGULAR 设置为 false 来禁用漂亮打印。

    【讨论】:

    • 非常感谢您的出色回应 - 从描述中看,我觉得烧瓶压缩是完美的,但由于集成起来非常简单,我不知道它是否真的有效。有什么方法可以测试实际发送了多少数据/压缩是否有效?
    • 如果 url 是公开可见的,您可以使用 checkgzipcompression.com 之类的东西,否则使用 Chrome,您可以打开开发人员工具并检查您的网络流量。响应应该包含一个标头条目Content-Encoding,它设置为gzip
    • 是的,我刚刚找到了 DevTools - Chrome 很棒的另一个原因。在那里我可以看到一个 100KB 的响应只有 16.8KB 和简单的烧瓶压缩扩展。惊人的。非常感谢。
    【解决方案3】:

    如果您正在寻找一个库来帮助通过 Gzip(或 Brotli)提供压缩内容,请尝试 flask-compress。这很简单;这可能就是您需要做的所有事情:

    from flask import Flask
    from flask_compress import Compress
    
    app = Flask(__name__)
    Compress(app)
    

    【讨论】:

      【解决方案4】:

      Ripper346's answer 启发,但不是为所有路线/视图手动编写它。最好添加一个 sn-p(与对库的外部依赖相比),它将在发送之前压缩响应。

      将以下内容添加到您的应用文件或任何合适的位置(例如 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
      

      然后在您的应用中:

      from flask import Flask
      from gzip_compress import GzipCompress
      
      app = Flask(__name__)
      GzipCompress(app)
      

      您可以设置 gzip 压缩级别和启动压缩的最小响应大小。它包括对 gzip 支持和响应代码的其他检查。

      【讨论】:

      • 如果你想压缩所有的路由很酷。此外,您可以考虑在 GzipCompress 上创建一个静态函数,以便仅在您有时想要压缩时使用它。您将在一个地方拥有一切
      【解决方案5】:

      suvigyavijay's answer 的衍生品,不使用尴尬的课程,io.BytesIO()gzip.GzipFile(不过,他做了很多繁重的工作,道具)。

      注意。我认为这适用于所有请求。

      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
      

      【讨论】:

        猜你喜欢
        • 2011-08-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多