【问题标题】:Compressing JSON sent via CGI in Python在 Python 中压缩通过 CGI 发送的 JSON
【发布时间】:2015-06-15 16:59:44
【问题描述】:

我目前正在开发的 webApp 需要客户端请求的大型 JSON 文件,使用 Python 在服务器上构建并发送回客户端。该解决方案是通过 CGI 实现的,并且在各个方面都正常工作。 在这个阶段,我只是使用各种技术来最小化返回给客户端的 JSON 对象的大小,大约为 5-10mb(不详细说明,这或多或少是固定的,并且不能在任何情况下延迟加载大大地)。 我们使用的主机不支持 mod_deflate 或 mod_gzip,所以虽然我们无法将 Apache 配置为使用 .htaccess 在服务器上自动创建 gzip 压缩的内容,但我认为我们仍然可以在客户端接收和解码只要正确设置 Content-encoding 标头即可。

我想知道的是,实现这一目标的最佳方法是什么。在 Python 中压缩某些东西是微不足道的。我已经知道该怎么做,但问题是: 如何以这样一种方式压缩数据,将其打印到输出流以通过 CGI 发送将被压缩并可供客户端读取?

这些文件必须根据输入数据动态创建,因此不能存储预制和预压缩文件,它们必须通过 webApp 中的 xhr 接收。

我最初的实验是使用 gzip 和 io.stringIO 压缩 JSON 字符串,然后将其打印到输出流,导致它以 Python 的正常字节格式打印,例如:b'\n\x91\x8c\xbc\xd4\ xc6\xd2\x19\x98\x14x\x0f1q!\xdc|C\xae\xe0 等,将请求膨胀到正常大小的两倍......

我想知道是否有人可以在这里为我指明正确的方向,告诉我如何实现这一点,如果确实有可能的话。 我希望我已经正确地表达了我的问题。 谢谢。

【问题讨论】:

    标签: python json xmlhttprequest cgi gzip


    【解决方案1】:

    我猜你使用print()(它首先将其参数转换为字符串,然后再将其发送到标准输出)或sys.stdout(它只接受 str 对象)。

    要直接写入stdout,可以使用sys.stdout.buffer,一个支持字节对象的类文件对象:

    import sys
    import gzip
    
    s = 'foo'*100
    
    sys.stdout.buffer.write(gzip.compress(s.encode()))
    

    提供有效的 gzip 数据:

    $ python3 foo.py | gunzip
    foofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoo
    

    【讨论】:

    • 感谢您的回复!以这种方式打印输出会导致从客户端加载时出现 500 错误,检查服务器日志我发现:[Fri Apr 10 10:11:28 2015] [error] [client 172.17.240.5] 来自脚本的格式错误的标头。 Bad header=\x1f\x8b\b: loader_main.cgi, referer: 请原谅我的无知,但我不确定为什么会发生这种情况。似乎也将数据编码为 ascii 也不合适,chrome 希望输出以正确的二进制形式提供服务。
    • sys.stdout.write('Content-type: application/octet-stream\n\n')
    • 这只是一个例子。您仍然必须先输出标题。
    • 我知道这一点。即使附加了有效的标题,您仍然会收到该错误,这是真正令人费解的部分。标题后甚至还有空行,所以我不知道为什么会出现损坏的标题错误。
    【解决方案2】:

    感谢 Valentin 和 Phillip 的回答! 我设法解决了这个问题,你们俩都为最终答案做出了贡献。原来它是事物的组合。 这是最终的有效代码:

        response = json.JSONEncoder().encode(loadData)  
        sys.stdout.write('Content-type: application/octet-stream\n')
        sys.stdout.write('Content-Encoding: gzip\n\n')
        sys.stdout.flush()
        sys.stdout.buffer.write(gzip.compress(response.encode()))
    

    在切换到 sys.stdout 而不是使用 print 来打印标题并刷新它设法正确读取的流之后。这很奇怪......总是有更多的东西要学。 再次感谢!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-09
      • 1970-01-01
      • 2010-09-19
      • 2012-07-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多